/* -*- mode: C; tab-width:8; -*- */ /* * Mesa 3-D graphics library * Version: 3.3 * * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * Original Mesa / 3Dfx device driver (C) 1999 David Bucciarelli, by the * terms stated above. * * Thank you for your contribution, David! * * Please make note of the above copyright/license statement. If you * contributed code or bug fixes to this code under the previous (GNU * Library) license and object to the new license, your code will be * removed at your request. Please see the Mesa docs/COPYRIGHT file * for more information. * * Additional Mesa/3Dfx driver developers: * Daryll Strauss * Keith Whitwell * * See fxapi.h for more revision/author details. */ /* fxapi.c - 3Dfx VooDoo/Mesa interface */ /******************************************************************** * * Function names: * fxMesa.... (The driver API) * fxDD.... (Mesa device driver functions) * fxTM.... (Texture manager functions) * fxSetup.... (Voodoo units setup functions) * fx.... (Internal driver functions) * * Data type names: * fxMesa.... (Public driver data types) * tfx.... (Private driver data types) * ******************************************************************** * * V0.30 - David Bucciarelli (davibu@tin.it) Humanware s.r.l. * - introduced a new MESA_GLX_FX related behavior * - the Glide fog table was built in a wrong way (using * gu* Glide function). Added the code for building the * table following the OpenGL specs. Thanks to Steve Baker * for highlighting the problem. * - fixed few problems in my and Keith's fxDDClear code * - merged my code with the Keith's one * - used the new BlendFunc Mesa device driver function * - used the new AlphaFunc Mesa device driver function * - used the new Enable Mesa device driver function * - fixed a bug related to fog in the Mesa core. Fog * were applied two times: at vertex level and at fragment * level (thanks to Steve Baker for reporting the problem) * - glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE) now works * (thanks to Jiri Pop for reporting the problem) * - the driver works fine with OpenGL Unreal * - fixed a bug in the Mesa core clipping code (related * to the q texture coordinate) * - introduced the support for the q texture coordinate * * Keith Whitwell (keithw@cableinet.co.uk) * - optimized the driver and written all the new code * required by the new Mesa-3.1 device driver API * and by the new Mesa-3.1 core changes * - written the cva support and many other stuff * * Brian Paul (brian_paul@avid.com) Avid Technology * - fixed display list share bug for MESA_GLX_FX = window/fullscreen * - fixed glClear/gl...Mask related problem * * Bert Schoenwaelder (bert@prinz-atm.CS.Uni-Magdeburg.De) * - the driver is now able to sleep when waiting for the completation * of multiple swapbuffer operations instead of wasting * CPU time (NOTE: you must uncomment the lines in the * fxMesaSwapBuffers function in order to enable this option) * * Eero Pajarre (epajarre@koti.tpo.fi) * - enabled the macro FLOAT_COLOR_TO_UBYTE_COLOR under * windows * - written an asm x86 optimized float->integer conversions * for windows * * Theodore Jump (tjump@cais.com) * - fixed a small problem in the __wglMonitor function of the * wgl emulator * - written the in-window-rendering hack support for windows * and Vooodoo1/2 cards * * V0.29 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - included in Mesa-3.0 * - now glGetString(GL_RENDERER) returns more information * about the hardware configuration: "Mesa Glide * CARD/ FB/ * TM/ TMU/" * where: CARD is the card used for the current context, * FB is the number of MB for the framebuffer, * TM is the number of MB for the texture memory, * TMU is the number of TMU. You can try to run * Mesa/demos/glinfo in order to have an example of the * output * - fixed a problem of the WGL emulator with the * OpenGL Optimizer 1.1 (thanks to Erwin Coumans for * the bug report) * - fixed some bug in the fxwgl.c code (thanks to * Peter Pettersson for a patch and a bug report) * * Theodore Jump (tjump@cais.com) * - written the SST_DUALHEAD support in the WGL emulator * * Daryll Strauss (daryll@harlot.rb.ca.us) * - fixed the Voodoo Rush support for the in window rendering * * V0.28 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - the only supported multitexture functions are GL_MODULATE * for texture set 0 and GL_MODULATE for texture set 1. In * all other cases, the driver falls back to pure software * rendering * - written the support for the new GL_EXT_multitexture * - written the DD_MAX_TEXTURE_COORD_SETS support in the * fxDDGetParameteri() function * - the driver falls back to pure software rendering when * texture mapping function is GL_BLEND * * V0.27 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - inluded in the Mesa-3.0beta5 * - written a smal extension (GL_FXMESA_global_texture_lod_bias) in * order to expose the LOD bias related Glide function * - fixed a bug fxDDWriteMonoRGBAPixels() * - the driver is now able to fallback to software rendering in * any case not directly supported by the hardware * - written the support for enabling/disabling dithering * - the in-window-rendering hack now works with any X11 screen * depth * - fixed a problem related to color/depth/alpha buffer clears * - fixed a problem when clearing buffer for a context with the * alpha buffer * - fixed a problem in the fxTMReloadSubMipMapLevel() function, * I have forget a "break;" (thanks to Joe Waters for the bug report) * - fixed a problem in the color format for the in window * rendering hack * - written the fxDDReadRGBAPixels function * - written the fxDDDepthTestPixelsGeneric function * - written the fxDDDepthTestSpanGeneric function * - written the fxDDWriteMonoRGBAPixels function * - written the fxDDWriteRGBAPixels function * - removed the multitexture emulation code for Voodoo board * with only one TMU * * Chris Prince * - fixed a new bug in the wglUseFontBitmaps code * * Ralf Knoesel (rknoesel@Stormfront.com) * - fixed a bug in the wglUseFontBitmaps code * * Rune Hasvold (runeh@ifi.uio.no) * - fixed a problem related to the aux usage in the fxBestResolution * function * - fixed the order of pixel formats in the WGL emulator * * Fredrik Hubinette (hubbe@hubbe.net) * - the driver shutdown the Glide for most common signals * * V0.26 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - included in the Mesa-3.0beta4 * - fixed a problem related to a my optimization for the Rune's * pixel-span optimization * - fixed a problem related to fxDDSetNearFar() and ctx->ProjectionMatrixType * (thanks to Ben "Ctrl-Alt-Delete" and the Raul Alonso's ssystem) * - fixed a small bug in the Rune's pixel-span optimization * - fixed a problem with GL_CCW (thanks to Curt Olson for and example * of the problem) * - grVertex setup code is now ready for the internal thread support * - fixed a no used optimization with clipped vertices in * grVertex setup code * - fixed a problem in the GL_LIGHT_MODEL_TWO_SIDE support (thanks * to Patrick H. Madden for a complete example of the bug) * * Rune Hasvold (runeh@ifi.uio.no) * - highly optimized the driver functions for writing pixel * span (2-3 times faster !) * * Axel W. Volley (volley@acm.org) Krauss-Maffei Wehrtechnik * - written the fxDDReadDepthSpanFloat() and fxDDReadDepthSpanInt() * functions * * V0.25 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - fixed a problem with Voodoo boards with only one TMU * - fixed a bug in the fxMesaCreateContext() * - now the GL_FRONT_AND_BACK works fine also with * the alpha buffer and/or antialiasing * - written the support for GL_FRONT_AND_BACK drawing but * it doesn't works with the alpha buffer and/or antialiasing * - fixed some bug in the Mesa core for glCopyTexSubImage * and glCopyTexImage functions (thanks to Mike Connell * for an example of the problem) * - make some small optimizations in the Mesa core in order * to save same driver call and state change for not very * well written applications * - introduced the NEW_DRVSTATE and make other optimizations * for minimizing state changes * - made a lot of optimizations in order to minimize state * changes * - it isn't more possible to create a context with the * depth buffer and the stancil buffer (it isn't yet supported) * - now the partial support for the Multitexture extension * works with Quake2 for windows * - vertex snap is not longer used for the Voodoo2 (FX_V2 * must be defined) * - done a lot of cleanup in the fxsetup.c file * - now the partial support for the Multitexture extension * works with GLQuake for windows * * Dieter Nuetzel (nuetzel@kogs.informatik.uni-hamburg.de) University of Hamburg * - fixed a problem in the asm code for Linux of the fxvsetup.c file * highlighted by the binutils-2.8.1.0.29. 'fildw' asm instruction * changed in 'fild' * * Kevin Hester (kevinh@glassworks.net) * - written the wglUseFontBitmaps() function in the WGL emulator * * V0.24 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - now the drive always uses per fragment fog * - written a small optimization in the points drawing function * - written the support for trilinear filtering with 2 TMUs * - written the first partial support for the Multitexture extension. * This task is quite hard because the color combine units work after * the two texture combine units and not before as required by the * Multitexture extension * - written a workaround in fxBestResolution() in order to solve a * problem with bzflag (it asks for 1x1 window !) * - changed the fxBestResolution() behavior. It now returns the larger * screen resolution supported by the hardware (instead of 640x480) * when it is unable to find an appropriate resolution that is large * enough for the requested size * - the driver is now able to use also the texture memory attached to * second TMU * - the texture memory manager is now able to work with two TMUs and * store texture maps in the memory attached to TMU0, TMU1 or to split * the mimpmap levels across TMUs in order to support trilinear filtering * - I have bought a Voodoo2 board ! * - the amount of frambuffer ram is now doubled when an SLI configuration * is detected * - solved a problem related to the fxDDTexParam() and fxTexInvalidate() * functions (thanks to Rune Hasvold for highlighting the problem) * - done some cleanup in the fxvsetup.c file, written * the FXVSETUP_FUNC macro * - done a lot of cleanup in data types and field names * * Rune Hasvold (runeh@ifi.uio.no) * - written the support for a right management of the auxiliary buffer. * You can now use an 800x600 screen without the depth and alpha * buffer * - written the support for a new pixel format (without the depth * and alpha buffer) in the WGL emulator * - fixed a bug in the window version of the GLUT (it was ever asking * for depth buffer) * * V0.23 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - included in the Mesa-3.0beta2 release * - written the support for the OpenGL 1.2 GL_TEXTURE_BASE_LEVEL * and GL_TEXTURE_MAX_LEVEL * - rewritten several functions for a more clean support of texture * mapping and in order to solve some bug * - the accumulation buffer works (it is bit slow beacuase it requires * to read/write from/to the Voodoo frame buffer but it works) * - fixed a bug in the fxDDReadRGBASpan driver function (the R and * B channels were read in the wrong order). Thanks to Jason Heym * for highlighting the problem * - written the support for multiple contexts on multiple boards. * you can now use the Mesa/Voodoo with multiple Voodoo Graphics * boards (for example with multiple screens or an HMD) * - the fxBestResolution() now check all available resolutions * and it is able to check the amount of framebuffer memory * before return a resolution * - modified the GLX/X11 driver in order to support all the * resolution available * - changed all function names. They should be now a bit more * readable * - written the Glide grVertex setup code for two TMU or * for Multitexture support with emulationa dn one TMU * - written the support for the new Mesa driver * function GetParametri * - small optimization/clean up in the texbind() function * - fixed a FPU precision problem for glOrtho and texture * mapping (thanks to Antti Juhani Huovilainen for an example * of the problem) * - written some small SGI OpenGL emulation code for the wgl, * the OpenGL Optimizer and Cosmo3D work fine under windows ! * - moved the point/line/triangle/quad support in the fxmesa7.c * - fixed a bug in the clear_color_depth() (thanks to Henk Kok * for an example of the problem) * - written a small workaround for Linux GLQuake, it asks * for the alpha buffer and the depth buffer at the some time * (but it never uses the alpha buffer) * - checked the antialiasing points, lines and polygons support. * It works fine * - written the support for standard OpenGL antialiasing using * blending. Lines support works fine (tested with BZflag) * while I have still to check the polygons and points support * - written the support for the alpha buffer. The driver is now * able to use the Voodoo auxiliary buffer as an alpha buffer * instead of a depth buffer. Also all the OpenGL blending * modes are now supported. But you can't request a context * with an alpha buffer AND a depth buffer at the some time * (this is an hardware limitation) * - written the support for switching between the fullscreen * rendering and the in-window-rendering hack on the fly * * Rune Hasvold (runeh@ifi.uio.no) * - fixed a bug in the texparam() function * * Brian Paul (brianp@elastic.avid.com) Avid Technology * - sources accomodated for the new Mesa 3.0beta1 * * V0.22 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - included with some v0.23 bug fix in the final release * of the Mesa-2.6 * - written the support for the MESA_WGL_FX env. var. but * not tested because I have only Voodoo Graphics boards * - fixed a bug in the backface culling code * (thanks to David Farrell for an example of the problem) * - fixed the "Quake2 elevator" bug * - GL_POLYGONS with 3/4 vertices are now drawn as * GL_TRIANLGES/GL_QUADS (a small optimization for GLQuake) * - fixed a bug in fxmesa6.h for GL_LINE_LOOP * - fixed a NearFarStack bug in the Mesa when applications * directly call glLoadMatrix to load a projection matrix * - done some cleanup in the fxmesa2.c file * - the driver no longer translates the texture maps * when the Mesa internal format and the Voodoo * format are the some (usefull for 1 byte texture maps * where the driver can directly use the Mesa texture * map). Also the amount of used memory is halfed * - fixed a bug for GL_DECAL and GL_RGBA * - fixed a bug in the clear_color_depth() * - tested the v0.22 with the Mesa-2.6beta2. Impressive * performances improvement thanks to the new Josh's * asm code (+10fps in the isosurf demo, +5fps in GLQuake * TIMEREFRESH) * - written a optimized version of the RenderVB Mesa driver * function. The Voodoo driver is now able to upload polygons * in the most common cases at a very good speed. Good * performance improvement for large set of small polygons * - optimized the asm code for setting up the color information * in the Glide grVertex structure * - fixed a bug in the fxmesa2.c asm code (the ClipMask[] * wasn't working) * * Josh Vanderhoof (joshv@planet.net) * - removed the flush() function because it isn't required * - limited the maximum number of swapbuffers in the Voodoo * commands FIFO (controlled by the env. var. MESA_FX_SWAP_PENDING) * * Holger Kleemiss (holger.kleemiss@metronet.de) STN Atlas Elektronik GmbH * - applied some patch for the Voodoo Rush * * V0.21 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - the driver is now able to take advantage of the ClipMask[], * ClipOrMask and ClipAndMask information also under Windows * - introduced a new function in the Mesa driver interface * ClearColorAndDepth(). Now the glClear() function is * 2 times faster (!) when you have to clear the color buffer * and the depth buffer at some time * - written the first version of the fxRenderVB() driver * function * - optimized the glTexImage() path * - removed the fxMesaTextureUsePalette() support * - fixed a bug in the points support (thanks to David Farrell * for an example of the problem) * - written the optimized path for glSubTexImage(), * introduced a new function in the Mesa driver interface * TexSubImage(...) * - fixed a bug for glColorMask and glDepthMask * - the wbuffer is not more used. The Voodoo driver uses * a standard 16bit zbuffer in all cases. It is more consistent * and now GLQuake and GLQuake2test work also with a GL_ZTRICK 0 * - the driver is now able to take advantage of the ClipMask[], * ClipOrMask and ClipAndMask information (under Linux); * - rewritten the setup_fx_units() function, now the texture * mapping support is compliant to the OpenGL specs (GL_BLEND * support is still missing). The LinuxGLQuake console correctly * fade in/out and transparent water of GLQuake2test works fine * - written the support for the env. var. FX_GLIDE_SWAPINTERVAL * - found a bug in the Mesa core. There is a roundup problem for * color values out of the [0.0,1.0] range * * Wonko * - fixed a Voodoo Rush related problem in the fxwgl.c * * Daryll Strauss * - written the scissor test support * * V0.20 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - written the closetmmanger() function in order to free all the memory * allocated by the Texture Memory Manager (it will be useful * when the support for multiple contexts/boards will be ready) * - now the Voodoo driver runs without printing any information, * define the env. var. MESA_FX_INFO if you want to read some * information about the hardware and some statistic * - written a small workaround for the "GLQuake multiplayer white box bug" * in the setup_fx_units() funxtions. I'm already rewriting * this function because it is the source of nearly all the current * Voodoo driver problems * - fixed the GLQuake texture misalignment problem (the texture * coordinates must be scaled between 0.0 and 256.0 and not * between 0.0 and 255.0) * - written the support for the GL_EXT_shared_texture_palette * - some small change for supporting the automatic building of the * OpenGL32.dll under the Windows platform * - the redefinition of a mipmap level is now a LOT faster. This path * is used by GLQuake for dynamic lighting with some call to glTexSubImage2D() * - the texture memory is now managed a set of 2MB blocks so * texture maps can't be allocated on a 2MB boundary. The new Pure3D * needs this kind of support (and probably any other Voodoo Graphics * board with more than 2MB of texture memory) * * Brian Paul (brianp@elastic.avid.com) Avid Technology * - added write_monocolor_span(), fixed bug in write_color_span() * - added test for stenciling in choosepoint/line/triangle functions * * Joe Waters (falc@attila.aegistech.com) Aegis * - written the support for the env. var. SST_SCREENREFRESH * * V0.19 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - written the 3Dfx Global Palette extension for GLQuake * - written the support for the GL_EXT_paletted_texture (it works only with GL_RGBA * palettes and the alpha value is ignored ... this is a limitation of the * the current Glide version and Voodoo hardware) * - fixed the amount of memory allocated for 8bit textures * - merged the under construction v0.19 driver with the Mesa 2.5 * - finally written the support for deleting textures * - introduced a new powerful texture memory manager: the texture memory * is used as a cache of the set of all defined texture maps. You can * now define several MB of texture maps also with a 2MB of texture memory * (the texture memory manager will do automatically all the swap out/swap in * work). The new texture memory manager has also * solved a lot of other bugs/no specs compliance/problems * related to the texture memory usage. The texture * manager code is inside the new fxmesa3.c file * - broken the fxmesa.c file in two files (fxmesa1.c and fxmesa2.c) * and done some code cleanup * - now is possible to redefine texture mipmap levels already defined * - fixed a problem with the amount of texture memory allocated for textures * with not all mipmap levels defined * - fixed a small problem with single buffer rendering * * Brian Paul (brianp@elastic.avid.com) Avid Technology * - read/write_color_span() now use front/back buffer correctly * - create GLvisual with 5,6,5 bits per pixel, not 8,8,8 * - removed a few ^M characters from fxmesa2.c file * * V0.18 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - the Mesa-2.4beta3 is finally using the driver quads support (the * previous Mesa versions have never taken any advantage from the quads support !) * - tested with the Glide 2.4 for Win * - ported all asm code to Linux * - ported the v0.18 to Linux (without asm code) * - back to Linux !!! * - optimized the SETUP macro (no more vertex snap for points and lines) * - optimized the SETUP macro (added one argument) * - the Mesa/Voodoo is now 20/30% for points, lines and small triangles ! * - performance improvement setting VBSIZE to 72 * - the GrVertex texture code is now written in asm * - the GrVertex zbuffer code is now written in asm * - the GrVertex wbuffer code is now written in asm * - the GrVertex gouraud code is now written in asm * - the GrVertex snap code is now written in asm * - changed the 8bit compressed texture maps in 8bit palette texture maps * support (it has the some advantage of compressed texture maps without the * problem of a fixed NCC table for all mipmap levels) * - written the support for 8bit compressed texture maps (but texture maps with * more than one mipmap level aren't working fine) * - finnaly everthing is working fine in MesaQuake ! * - fixed a bug in the computation of texture mapping coordinates (I have found * the bug thanks to MesaQuake !) * - written the GL_REPLACE support (mainly for MesaQuake) * - written the support for textures with not all mipmap levels defined * - rewritten all the Texture memory stuff * - written the MesaQuake support (define MESAQUAKE) * - working with a ZBuffer if glOrtho or not int the default glDepthRange, * otherwise working with the WBuffer * written the glDepthRange support * * Diego Picciani (d.picciani@novacomp.it) Nova Computer s.r.l. * - written the fxCloseHardware() and the fxQuaryHardware() (mainly * for the VoodooWGL emulator) * * Brian Paul (brianp@elastic.avid.com) Avid Technology * - implemented read/write_color_span() so glRead/DrawPixels() works * - now needs Glide 2.3 or later. Removed GLIDE_FULL_SCREEN and call to grSstOpen() * * V0.17 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - optimized the bitmap support (66% faster) * - tested with the Mesa 2.3beta2 * * Diego Picciani (d.picciani@novacomp.it) Nova Computer s.r.l. * - solved a problem with the drawbitmap() and the Voodoo Rush * (GR_ORIGIN_LOWER_LEFT did not work with the Stingray) * * Brian Paul (brianp@elastic.avid.com) Avid Technology * - linux stuff * - general code clean-up * - added attribList parameter to fxMesaCreateContext() * - single buffering works now * - VB colors are now GLubytes, removed ColorShift stuff * * Paul Metzger * - linux stuff * * V0.16 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - written the quadfunc support (no performance improvement) * - written the support for the new Mesa 2.3beta1 driver interface (Wow ! It is faaaster) * - rewritten the glBitmap support for the Glide 2.3 (~35% slower !) * - written the glBitmap support for the most common case (fonts) * * Jack Palevich * - Glide 2.3 porting * * Diego Picciani (d.picciani@novacomp.it) Nova Computer s.r.l. * - extended the fxMesaCreateContext() and fxMesaCreateBestContext() * functions in order to support also the Voodoo Rush * - tested with the Hercules Stingray 128/3D (The rendering in a window works !) * * V0.15 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - written the GL_LUMINANCE_ALPHA support * - written the GL_ALPHA support * - written the GL_LUMINANCE support * - now SETUP correctly set color for mono color sequences * - written the 9x1,10x1,...,1x9,1x10,... texture map ratio support * - written the no square texture map support * - the fog table is no more rebuilt inside setup_fx_units() each time * * Henri Fousse (arnaud@pobox.oleane.com) Thomson Training & Simulation * - written (not yet finished: no texture mapping) support for glOrtho * - some change to setup functions * - the fog support is now fully compatible with the standard OpenGL * - rewritten several parts of the driver in order to take * advantage of meshes (40% faster !!!) * * V0.14 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - now glAlphaFunc() works * - now glDepthMask() works * - solved a mipmap problem when using more than one texture * - moved ti, texid and wscale inside the fxMesaContext (now we can * easy support more ctx and more boards) * - the management of the fxMesaContext was completly broken ! * - solved several problems about Alpha and texture Alpha * - 4 (RGBA) texture channels supported * - setting the default color to white * * Henri Fousse (arnaud@pobox.oleane.com) Thomson Training & Simulation * - small change to fxMesaCreateContext() and fxMesaMakeCurrent() * - written the fog support * - setting the default clear color to black * - written cleangraphics() for the onexit() function * - written fxMesaCreateBestContext() * * V0.13 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - now glBlendFunc() works for all glBlendFunc without DST_ALPHA * (because the alpha buffer is not yet implemented) * - now fxMesaCreateContext() accept resolution and refresh rate * - fixed a bug for texture mapping: the w (alias z) must be set * also without depth buffer * - fixed a bug for texture image with width!=256 * - written texparam() * - written all point, line and triangle functions for all possible supported * contexts and the driver is slight faster with points, lines and small triangles * - fixed a small bug in fx/fxmesa.h (glOrtho) * * V0.12 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - glDepthFunc supported * - introduced a trick to discover the far plane distance * (see fxMesaSetFar and fx/fxmesa.h) * - now the wbuffer works with homogeneous coordinate (and it * doesn't work with a glOrtho projection :) * - solved several problems with homogeneous coordinate and texture mapping * - fixed a bug in all line functions * - fixed a clear framebuffer bug * - solved a display list/teximg problem (but use * glBindTexture: it is several times faster) * * V0.11 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - introduced texture mapping support (not yet finished !) * - tested with Mesa2.2b6 * - the driver is faster * - written glFlush/glFinish * - the driver print a lot of info about the Glide lib * * v0.1 - David Bucciarelli (tech.hmw@plus.it) Humanware s.r.l. * - Initial revision * */ #ifdef HAVE_CONFIG_H #include "conf.h" #endif #if defined(FX) #include "fxdrv.h" fxMesaContext fxMesaCurrentCtx=NULL; /* * Status of 3Dfx hardware initialization */ static int glbGlideInitialized=0; static int glb3DfxPresent=0; static int glbTotNumCtx=0; GrHwConfiguration glbHWConfig; int glbCurrentBoard=0; #if defined(__WIN32__) static int cleangraphics(void) { glbTotNumCtx=1; fxMesaDestroyContext(fxMesaCurrentCtx); return 0; } #elif defined(__linux__) static void cleangraphics(void) { glbTotNumCtx=1; fxMesaDestroyContext(fxMesaCurrentCtx); } static void cleangraphics_handler(int s) { fprintf(stderr,"fxmesa: Received a not handled signal %d\n",s); cleangraphics(); /* abort(); */ exit(1); } #endif /* * Select the Voodoo board to use when creating * a new context. */ GLboolean GLAPIENTRY fxMesaSelectCurrentBoard(int n) { fxQueryHardware(); if((n<0) || (n>=glbHWConfig.num_sst)) return GL_FALSE; glbCurrentBoard=n; return GL_TRUE; } fxMesaContext GLAPIENTRY fxMesaGetCurrentContext(void) { return fxMesaCurrentCtx; } void GLAPIENTRY fxMesaSetNearFar(GLfloat n, GLfloat f) { if(fxMesaCurrentCtx) fxDDSetNearFar(fxMesaCurrentCtx->glCtx,n,f); } /* * The extension GL_FXMESA_global_texture_lod_bias */ /* XXX this function may soon go away in favor of GL_EXT_texture_lod_bias */ extern void GLAPIENTRY glGlobalTextureLODBiasFXMESA(GLfloat biasVal); void GLAPIENTRY glGlobalTextureLODBiasFXMESA(GLfloat biasVal) { grTexLodBiasValue(GR_TMU0,biasVal); if(fxMesaCurrentCtx->haveTwoTMUs) grTexLodBiasValue(GR_TMU1,biasVal); } /* * The 3Dfx Global Palette extension for GLQuake. * More a trick than a real extesion, use the shared global * palette extension. */ extern void GLAPIENTRY gl3DfxSetPaletteEXT(GLuint *pal); /* silence warning */ void GLAPIENTRY gl3DfxSetPaletteEXT(GLuint *pal) { fxMesaContext fxMesa =fxMesaCurrentCtx; if (MESA_VERBOSE&VERBOSE_DRIVER) { int i; fprintf(stderr,"fxmesa: gl3DfxSetPaletteEXT()\n"); for(i=0;i<256;i++) fprintf(stderr,"%x\n",pal[i]); } if(fxMesa) { fxMesa->haveGlobalPaletteTexture=1; FX_grTexDownloadTable(GR_TMU0,GR_TEXTABLE_PALETTE,(GuTexPalette *)pal); if (fxMesa->haveTwoTMUs) FX_grTexDownloadTable(GR_TMU1,GR_TEXTABLE_PALETTE,(GuTexPalette *)pal); } } static GrScreenResolution_t fxBestResolution(int width, int height, int aux) { static int resolutions[][5]={ { 512, 384, GR_RESOLUTION_512x384, 2, 2 }, { 640, 400, GR_RESOLUTION_640x400, 2, 2 }, { 640, 480, GR_RESOLUTION_640x480, 2, 2 }, { 800, 600, GR_RESOLUTION_800x600, 4, 2 }, { 960, 720, GR_RESOLUTION_960x720, 6, 4 } #ifdef GR_RESOLUTION_1024x768 ,{ 1024, 768, GR_RESOLUTION_1024x768, 8, 4 } #endif #ifdef GR_RESOLUTION_1280x1024 ,{ 1024, 768, GR_RESOLUTION_1280x1024, 8, 8 } #endif #ifdef GR_RESOLUTION_1600x1200 ,{ 1024, 768, GR_RESOLUTION_1600x1200, 16, 8 } #endif }; int NUM_RESOLUTIONS = sizeof(resolutions) / (sizeof(int)*5); int i,fbmem; GrScreenResolution_t lastvalidres=resolutions[1][2]; fxQueryHardware(); if(glbHWConfig.SSTs[glbCurrentBoard].type==GR_SSTTYPE_VOODOO) { fbmem=glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.fbRam; if(glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.sliDetect) fbmem*=2; } else if(glbHWConfig.SSTs[glbCurrentBoard].type==GR_SSTTYPE_SST96) fbmem=glbHWConfig.SSTs[glbCurrentBoard].sstBoard.SST96Config.fbRam; else fbmem=2; /* A work around for BZFlag */ if((width==1) && (height==1)) { width=640; height=480; } for(i=0;i0) { aux=1; break; } } res=fxBestResolution(width,height,aux); return fxMesaCreateContext(win,res,refresh,attribList); } #if 0 void fxsignals() { signal(SIGINT,SIG_IGN); signal(SIGHUP,SIG_IGN); signal(SIGPIPE,SIG_IGN); signal(SIGFPE,SIG_IGN); signal(SIGBUS,SIG_IGN); signal(SIGILL,SIG_IGN); signal(SIGSEGV,SIG_IGN); signal(SIGTERM,SIG_IGN); } #endif /* * Create a new FX/Mesa context and return a handle to it. */ fxMesaContext GLAPIENTRY fxMesaCreateContext(GLuint win, GrScreenResolution_t res, GrScreenRefresh_t ref, const GLint attribList[]) { fxMesaContext fxMesa = NULL; int i,type; int aux; GLboolean doubleBuffer=GL_FALSE; GLboolean alphaBuffer=GL_FALSE; GLboolean verbose=GL_FALSE; GLint depthSize=0; GLint stencilSize=0; GLint accumSize=0; GLcontext *shareCtx = NULL; GLcontext *ctx = 0; /*FX_GrContext_t glideContext = 0;*/ char *errorstr; if (MESA_VERBOSE&VERBOSE_DRIVER) { fprintf(stderr,"fxmesa: fxMesaCreateContext() Start\n"); } if(getenv("MESA_FX_INFO")) verbose=GL_TRUE; aux=0; i=0; while(attribList[i]!=FXMESA_NONE) { switch (attribList[i]) { case FXMESA_DOUBLEBUFFER: doubleBuffer=GL_TRUE; break; case FXMESA_ALPHA_SIZE: i++; alphaBuffer=attribList[i]>0; if(alphaBuffer) aux=1; break; case FXMESA_DEPTH_SIZE: i++; depthSize=attribList[i]; if(depthSize) { aux=1; depthSize = 16; } break; case FXMESA_STENCIL_SIZE: i++; stencilSize=attribList[i]; break; case FXMESA_ACCUM_SIZE: i++; accumSize=attribList[i]; break; /* XXX ugly hack here for sharing display lists */ #define FXMESA_SHARE_CONTEXT 990099 /* keep in sync with xmesa1.c! */ case FXMESA_SHARE_CONTEXT: i++; { const void *vPtr = &attribList[i]; GLcontext **ctx = (GLcontext **) vPtr; shareCtx = *ctx; } break; default: if (MESA_VERBOSE&VERBOSE_DRIVER) { fprintf(stderr,"fxmesa: fxMesaCreateContext() End (defualt)\n"); } return NULL; } i++; } /* A workaround for Linux GLQuake */ if(depthSize && alphaBuffer) alphaBuffer=0; if(verbose) fprintf(stderr,"Mesa fx Voodoo Device Driver v0.30\nWritten by David Bucciarelli (davibu@tin.it.it)\n"); if((type=fxQueryHardware()) < 0) { fprintf(stderr,"fx Driver: ERROR no Voodoo1/2 Graphics or Voodoo Rush !\n"); return NULL; } if(type==GR_SSTTYPE_VOODOO) win=0; grSstSelect(glbCurrentBoard); fxMesa=(fxMesaContext)calloc(1,sizeof(struct tfxMesaContext)); if(!fxMesa) { errorstr = "malloc"; goto errorhandler; } if(glbHWConfig.SSTs[glbCurrentBoard].type==GR_SSTTYPE_VOODOO) fxMesa->haveTwoTMUs=(glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.nTexelfx > 1); else if(glbHWConfig.SSTs[glbCurrentBoard].type==GR_SSTTYPE_SST96) fxMesa->haveTwoTMUs=(glbHWConfig.SSTs[glbCurrentBoard].sstBoard.SST96Config.nTexelfx > 1); else fxMesa->haveTwoTMUs=GL_FALSE; fxMesa->haveDoubleBuffer=doubleBuffer; fxMesa->haveAlphaBuffer=alphaBuffer; fxMesa->haveGlobalPaletteTexture=GL_FALSE; fxMesa->haveZBuffer=depthSize ? 1 : 0; fxMesa->verbose=verbose; fxMesa->board=glbCurrentBoard; fxMesa->glideContext = FX_grSstWinOpen((FxU32)win,res,ref, #if FXMESA_USE_ARGB GR_COLORFORMAT_ARGB, #else GR_COLORFORMAT_ABGR, #endif GR_ORIGIN_LOWER_LEFT, 2,aux); if (!fxMesa->glideContext){ errorstr = "grSstWinOpen"; goto errorhandler; } /* Pixel tables are use during pixel read-back */ #if FXMESA_USE_ARGB fxInitPixelTables(fxMesa, GL_FALSE); /* Force RGB pixel order */ #else if (glbHWConfig.SSTs[glbCurrentBoard].type == GR_SSTTYPE_VOODOO) { /* jk991130 - GROSS HACK!!! - Voodoo 3s don't use BGR!! * the only way to tell if it's a Voodoo 3 at this stage of the * ballgame (no Glide 3.x for linux *yet*) is to query the # of TMUs * as Voodoo3s have 2 TMUs on board, Banshee has only 1 * Thanks to Joseph Kain for that one */ GrVoodooConfig_t *voodoo; voodoo = &glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig; printf("nTexelfx %d\n", voodoo->nTexelfx); printf("fbRam %d\n", voodoo->fbRam); printf("fbiRev %d\n", voodoo->fbiRev); if (voodoo->nTexelfx == 2 && voodoo->fbiRev != 260) { /* RGB pixel order (Voodoo3, but some Quantum3D models) */ fxInitPixelTables(fxMesa, GL_FALSE); } else { /* BGR pixel order on Voodoo1/2, or certain Quantum3D models */ fxInitPixelTables(fxMesa, GL_TRUE); } } else { fxInitPixelTables(fxMesa, GL_FALSE); /* use RGB pixel order otherwise */ } #endif fxMesa->width=FX_grSstScreenWidth(); fxMesa->height=FX_grSstScreenHeight(); fxMesa->clipMinX = 0; fxMesa->clipMaxX = fxMesa->width; fxMesa->clipMinY = 0; fxMesa->clipMaxY = fxMesa->height; fxMesa->screen_width = fxMesa->width; fxMesa->screen_height = fxMesa->height; fxMesa->x_offset = 0; fxMesa->y_offset = 0; fxMesa->y_delta = 0; fxMesa->needClip = 0; if(verbose) fprintf(stderr,"Glide screen size: %dx%d\n", (int)FX_grSstScreenWidth(),(int)FX_grSstScreenHeight()); fxMesa->glVis=gl_create_visual(GL_TRUE, /* RGB mode */ alphaBuffer, doubleBuffer, GL_FALSE, /* stereo */ depthSize, /* depth_size */ stencilSize, /* stencil_size */ accumSize, /* accum_size */ 0, /* index bits */ 5,6,5,0); /* RGBA bits */ if (!fxMesa->glVis) { errorstr = "gl_create_visual"; goto errorhandler; } ctx = fxMesa->glCtx=gl_create_context(fxMesa->glVis, shareCtx, /* share list context */ (void *) fxMesa, GL_TRUE); if (!ctx) { errorstr = "gl_create_context"; goto errorhandler; } if (!fxDDInitFxMesaContext( fxMesa )) { errorstr = "fxDDInitFxMesaContext failed"; goto errorhandler; } fxMesa->glBuffer=gl_create_framebuffer(fxMesa->glVis, GL_FALSE, /* no software depth */ fxMesa->glVis->StencilBits > 0, fxMesa->glVis->AccumBits > 0, fxMesa->glVis->AlphaBits > 0 ); if (!fxMesa->glBuffer) { errorstr = "gl_create_framebuffer"; goto errorhandler; } glbTotNumCtx++; /* install signal handlers */ #if defined(__linux__) /* Only install if environment var. is not set. */ if (fxMesa->glCtx->CatchSignals && !getenv("MESA_FX_NO_SIGNALS")) { signal(SIGINT,cleangraphics_handler); signal(SIGHUP,cleangraphics_handler); signal(SIGPIPE,cleangraphics_handler); signal(SIGFPE,cleangraphics_handler); signal(SIGBUS,cleangraphics_handler); signal(SIGILL,cleangraphics_handler); signal(SIGSEGV,cleangraphics_handler); signal(SIGTERM,cleangraphics_handler); } #endif if (MESA_VERBOSE&VERBOSE_DRIVER) { fprintf(stderr,"fxmesa: fxMesaCreateContext() End\n"); } return fxMesa; errorhandler: if (fxMesa) { if (fxMesa->glideContext) FX_grSstWinClose(fxMesa->glideContext); fxMesa->glideContext = 0; if (fxMesa->state) free(fxMesa->state); if (fxMesa->fogTable) free(fxMesa->fogTable); if (fxMesa->glBuffer) gl_destroy_framebuffer(fxMesa->glBuffer); if (fxMesa->glVis) gl_destroy_visual(fxMesa->glVis); if (fxMesa->glCtx) gl_destroy_context(fxMesa->glCtx); free(fxMesa); } if (MESA_VERBOSE&VERBOSE_DRIVER) { fprintf(stderr,"fxmesa: fxMesaCreateContext() End (%s)\n",errorstr); } return NULL; } /* * Function to set the new window size in the context (mainly for the Voodoo Rush) */ void GLAPIENTRY fxMesaUpdateScreenSize(fxMesaContext fxMesa) { fxMesa->width=FX_grSstScreenWidth(); fxMesa->height=FX_grSstScreenHeight(); } /* * Destroy the given FX/Mesa context. */ void GLAPIENTRY fxMesaDestroyContext(fxMesaContext fxMesa) { if (MESA_VERBOSE&VERBOSE_DRIVER) { fprintf(stderr,"fxmesa: fxMesaDestroyContext()\n"); } if(fxMesa) { gl_destroy_visual(fxMesa->glVis); gl_destroy_context(fxMesa->glCtx); gl_destroy_framebuffer(fxMesa->glBuffer); glbTotNumCtx--; fxCloseHardware(); FX_grSstWinClose(fxMesa->glideContext); if(fxMesa->verbose) { fprintf(stderr,"Misc Stats:\n"); fprintf(stderr," # swap buffer: %u\n",fxMesa->stats.swapBuffer); if(!fxMesa->stats.swapBuffer) fxMesa->stats.swapBuffer=1; fprintf(stderr,"Textures Stats:\n"); fprintf(stderr," Free texture memory on TMU0: %d:\n",fxMesa->freeTexMem[FX_TMU0]); if(fxMesa->haveTwoTMUs) fprintf(stderr," Free texture memory on TMU1: %d:\n",fxMesa->freeTexMem[FX_TMU1]); fprintf(stderr," # request to TMM to upload a texture objects: %u\n", fxMesa->stats.reqTexUpload); fprintf(stderr," # request to TMM to upload a texture objects per swapbuffer: %.2f\n", fxMesa->stats.reqTexUpload/(float)fxMesa->stats.swapBuffer); fprintf(stderr," # texture objects uploaded: %u\n", fxMesa->stats.texUpload); fprintf(stderr," # texture objects uploaded per swapbuffer: %.2f\n", fxMesa->stats.texUpload/(float)fxMesa->stats.swapBuffer); fprintf(stderr," # MBs uploaded to texture memory: %.2f\n", fxMesa->stats.memTexUpload/(float)(1<<20)); fprintf(stderr," # MBs uploaded to texture memory per swapbuffer: %.2f\n", (fxMesa->stats.memTexUpload/(float)fxMesa->stats.swapBuffer)/(float)(1<<20)); } if (fxMesa->state) free(fxMesa->state); if (fxMesa->fogTable) free(fxMesa->fogTable); fxTMClose(fxMesa); free(fxMesa); } if(fxMesa==fxMesaCurrentCtx) fxMesaCurrentCtx=NULL; } /* * Make the specified FX/Mesa context the current one. */ void GLAPIENTRY fxMesaMakeCurrent(fxMesaContext fxMesa) { if (MESA_VERBOSE&VERBOSE_DRIVER) { fprintf(stderr,"fxmesa: fxMesaMakeCurrent(...) Start\n"); } if(!fxMesa) { gl_make_current(NULL,NULL); fxMesaCurrentCtx=NULL; if (MESA_VERBOSE&VERBOSE_DRIVER) { fprintf(stderr,"fxmesa: fxMesaMakeCurrent(NULL) End\n"); } return; } /* if this context is already the current one, we can return early */ if (fxMesaCurrentCtx == fxMesa && fxMesaCurrentCtx->glCtx == gl_get_current_context()) { if (MESA_VERBOSE&VERBOSE_DRIVER) { fprintf(stderr,"fxmesa: fxMesaMakeCurrent(fxMesaCurrentCtx==fxMesa) End\n"); } return; } if(fxMesaCurrentCtx) grGlideGetState((GrState*)fxMesaCurrentCtx->state); fxMesaCurrentCtx=fxMesa; grSstSelect(fxMesa->board); grGlideSetState((GrState*)fxMesa->state); gl_make_current(fxMesa->glCtx,fxMesa->glBuffer); fxSetupDDPointers(fxMesa->glCtx); /* The first time we call MakeCurrent we set the initial viewport size */ if(fxMesa->glCtx->Viewport.Width==0) gl_Viewport(fxMesa->glCtx,0,0,fxMesa->width,fxMesa->height); if (MESA_VERBOSE&VERBOSE_DRIVER) { fprintf(stderr,"fxmesa: fxMesaMakeCurrent(...) End\n"); } } /* * Swap front/back buffers for current context if double buffered. */ void GLAPIENTRY fxMesaSwapBuffers(void) { if (MESA_VERBOSE&VERBOSE_DRIVER) { fprintf(stderr,"fxmesa: ------------------------------- fxMesaSwapBuffers() -------------------------------\n"); } if(fxMesaCurrentCtx) { FLUSH_VB( fxMesaCurrentCtx->glCtx, "swap buffers" ); if(fxMesaCurrentCtx->haveDoubleBuffer) { grBufferSwap(fxMesaCurrentCtx->swapInterval); /* * Don't allow swap buffer commands to build up! */ while(FX_grGetInteger(FX_PENDING_BUFFERSWAPS)>fxMesaCurrentCtx->maxPendingSwapBuffers) /* The driver is able to sleep when waiting for the completation of multiple swapbuffer operations instead of wasting CPU time (NOTE: you must uncomment the following line in the in order to enable this option) */ /* usleep(10000); */ ; fxMesaCurrentCtx->stats.swapBuffer++; } } } /* * Query 3Dfx hardware presence/kind */ int GLAPIENTRY fxQueryHardware(void) { if (MESA_VERBOSE&VERBOSE_DRIVER) { fprintf(stderr,"fxmesa: fxQueryHardware() Start\n"); } if(!glbGlideInitialized) { grGlideInit(); if(FX_grSstQueryHardware(&glbHWConfig)) { grSstSelect(glbCurrentBoard); glb3DfxPresent=1; if(getenv("MESA_FX_INFO")) { char buf[80]; FX_grGlideGetVersion(buf); fprintf(stderr,"Using Glide V%s\n",""); fprintf(stderr,"Number of boards: %d\n",glbHWConfig.num_sst); if(glbHWConfig.SSTs[glbCurrentBoard].type==GR_SSTTYPE_VOODOO) { fprintf(stderr,"Framebuffer RAM: %d\n", glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.sliDetect ? (glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.fbRam*2) : glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.fbRam); fprintf(stderr,"Number of TMUs: %d\n", glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.nTexelfx); fprintf(stderr,"SLI detected: %d\n", glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.sliDetect); } else if(glbHWConfig.SSTs[glbCurrentBoard].type==GR_SSTTYPE_SST96) { fprintf(stderr,"Framebuffer RAM: %d\n", glbHWConfig.SSTs[glbCurrentBoard].sstBoard.SST96Config.fbRam); fprintf(stderr,"Number of TMUs: %d\n", glbHWConfig.SSTs[glbCurrentBoard].sstBoard.SST96Config.nTexelfx); } } } else glb3DfxPresent=0; glbGlideInitialized=1; #if defined(__WIN32__) onexit((_onexit_t)cleangraphics); #elif defined(__linux__) /* Only register handler if environment variable is not defined. */ if (!getenv("MESA_FX_NO_SIGNALS")) { atexit(cleangraphics); } #endif } if(!glb3DfxPresent) { if (MESA_VERBOSE&VERBOSE_DRIVER) { fprintf(stderr,"fxmesa: fxQueryHardware() End (-1)\n"); } return(-1); } if (MESA_VERBOSE&VERBOSE_DRIVER) { fprintf(stderr,"fxmesa: fxQueryHardware() End (voodooo)\n"); } return(glbHWConfig.SSTs[glbCurrentBoard].type); } /* * Shutdown Glide library */ void GLAPIENTRY fxCloseHardware(void) { if(glbGlideInitialized) { if(getenv("MESA_FX_INFO")) { GrSstPerfStats_t st; FX_grSstPerfStats(&st); fprintf(stderr,"Pixels Stats:\n"); fprintf(stderr," # pixels processed (minus buffer clears): %u\n",(unsigned)st.pixelsIn); fprintf(stderr," # pixels not drawn due to chroma key test failure: %u\n",(unsigned)st.chromaFail); fprintf(stderr," # pixels not drawn due to depth test failure: %u\n",(unsigned)st.zFuncFail); fprintf(stderr," # pixels not drawn due to alpha test failure: %u\n",(unsigned)st.aFuncFail); fprintf(stderr," # pixels drawn (including buffer clears and LFB writes): %u\n",(unsigned)st.pixelsOut); } if(glbTotNumCtx==0) { grGlideShutdown(); glbGlideInitialized=0; } } } #else /* * Need this to provide at least one external definition. */ int gl_fx_dummy_function_api(void) { return 0; } #endif /* FX */