Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / dri / tdfx / tdfx_span.c
1 /* -*- mode: c; c-basic-offset: 3 -*-
2  *
3  * Copyright 2000 VA Linux Systems Inc., Fremont, California.
4  *
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
23  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26
27 /*
28  * Original rewrite:
29  *      Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
30  *
31  * Authors:
32  *      Gareth Hughes <gareth@valinux.com>
33  *      Brian Paul <brianp@valinux.com>
34  *      Keith Whitwell <keith@tungstengraphics.com>
35  *
36  */
37
38 #include "tdfx_context.h"
39 #include "tdfx_lock.h"
40 #include "tdfx_span.h"
41 #include "tdfx_render.h"
42 #include "swrast/swrast.h"
43
44
45 #define DBG 0
46
47
48 #define LOCAL_VARS                                                      \
49    driRenderbuffer *drb = (driRenderbuffer *) rb;                       \
50    __DRIdrawable *const dPriv = drb->dPriv;                     \
51    GLuint pitch = drb->backBuffer ? info.strideInBytes                  \
52      : (drb->pitch * drb->cpp);                                         \
53    const GLuint bottom = dPriv->h - 1;                                  \
54    char *buf = (char *)((char *)info.lfbPtr +                           \
55                          (dPriv->x * drb->cpp) +                        \
56                          (dPriv->y * pitch));                           \
57    GLuint p;                                                            \
58    (void) buf; (void) p;
59
60
61 #define Y_FLIP(_y)              (bottom - _y)
62
63
64 #define HW_WRITE_LOCK()                                                 \
65    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);                           \
66    GrLfbInfo_t info;                                                    \
67    FLUSH_BATCH( fxMesa );                                               \
68    UNLOCK_HARDWARE( fxMesa );                                           \
69    LOCK_HARDWARE( fxMesa );                                             \
70    info.size = sizeof(GrLfbInfo_t);                                     \
71    if (fxMesa->Glide.grLfbLock(GR_LFB_WRITE_ONLY, fxMesa->DrawBuffer,   \
72                                LFB_MODE, GR_ORIGIN_UPPER_LEFT, FXFALSE, \
73                                &info)) {
74
75 #define HW_WRITE_UNLOCK()                                               \
76       fxMesa->Glide.grLfbUnlock( GR_LFB_WRITE_ONLY, fxMesa->DrawBuffer );\
77    }
78
79
80 #define HW_READ_LOCK()                                                  \
81    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);                           \
82    GrLfbInfo_t info;                                                    \
83    FLUSH_BATCH( fxMesa );                                               \
84    UNLOCK_HARDWARE( fxMesa );                                           \
85    LOCK_HARDWARE( fxMesa );                                             \
86    info.size = sizeof(GrLfbInfo_t);                                     \
87    if ( fxMesa->Glide.grLfbLock( GR_LFB_READ_ONLY, fxMesa->ReadBuffer,  \
88                    LFB_MODE, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info ) )   \
89    {
90
91 #define HW_READ_UNLOCK()                                                \
92       fxMesa->Glide.grLfbUnlock( GR_LFB_READ_ONLY, fxMesa->ReadBuffer );\
93    }
94
95
96 #define HW_WRITE_CLIPLOOP()                                             \
97       do {                                                              \
98          int _nc = fxMesa->numClipRects;                                \
99          while (_nc--) {                                                \
100             int minx = fxMesa->pClipRects[_nc].x1 - fxMesa->x_offset;   \
101             int miny = fxMesa->pClipRects[_nc].y1 - fxMesa->y_offset;   \
102             int maxx = fxMesa->pClipRects[_nc].x2 - fxMesa->x_offset;   \
103             int maxy = fxMesa->pClipRects[_nc].y2 - fxMesa->y_offset;
104
105 #define HW_READ_CLIPLOOP()                                              \
106       do {                                                              \
107          const __DRIdrawable *dPriv = fxMesa->driDrawable;      \
108          drm_clip_rect_t *rect = dPriv->pClipRects;                     \
109          int _nc = dPriv->numClipRects;                                 \
110          while (_nc--) {                                                \
111             const int minx = rect->x1 - fxMesa->x_offset;               \
112             const int miny = rect->y1 - fxMesa->y_offset;               \
113             const int maxx = rect->x2 - fxMesa->x_offset;               \
114             const int maxy = rect->y2 - fxMesa->y_offset;               \
115             rect++;
116
117 #define HW_ENDCLIPLOOP()                                                \
118          }                                                              \
119       } while (0)
120
121
122
123 #define LFB_MODE        GR_LFBWRITEMODE_565
124
125
126 /* 16 bit, RGB565 color spanline and pixel functions */                 \
127
128 #undef INIT_MONO_PIXEL
129 #define INIT_MONO_PIXEL(p, color) \
130   p = TDFXPACKCOLOR565( color[0], color[1], color[2] )
131
132
133 #define WRITE_RGBA( _x, _y, r, g, b, a )                                \
134    *(GLushort *)(buf + _x*2 + _y*pitch) = ((((int)r & 0xf8) << 8) |     \
135                                            (((int)g & 0xfc) << 3) |     \
136                                            (((int)b & 0xf8) >> 3))
137
138 #define WRITE_PIXEL( _x, _y, p )                                        \
139     *(GLushort *)(buf + _x*2 + _y*pitch) = p
140
141 #define READ_RGBA( rgba, _x, _y )                                       \
142     do {                                                                \
143         GLushort p = *(GLushort *)(buf + _x*2 + _y*pitch);              \
144         rgba[0] = (((p >> 11) & 0x1f) * 255) / 31;                      \
145         rgba[1] = (((p >>  5) & 0x3f) * 255) / 63;                      \
146         rgba[2] = (((p >>  0) & 0x1f) * 255) / 31;                      \
147         rgba[3] = 0xff;                                                 \
148     } while (0)
149
150 #define TAG(x) tdfx##x##_RGB565
151 #define BYTESPERPIXEL 2
152 #include "spantmp.h"
153 #undef BYTESPERPIXEL
154
155
156 /* 16 bit, BGR565 color spanline and pixel functions */                 \
157 #if 0
158
159 #define WRITE_RGBA( _x, _y, r, g, b, a )                                \
160    *(GLushort *)(buf + _x*2 + _y*pitch) = ((((int)b & 0xf8) << 8) |     \
161                                            (((int)g & 0xfc) << 3) |     \
162                                            (((int)r & 0xf8) >> 3))
163
164 #define WRITE_PIXEL( _x, _y, p )                                        \
165     *(GLushort *)(buf + _x*2 + _y*pitch) = p
166
167 #define READ_RGBA( rgba, _x, _y )                                       \
168     do {                                                                \
169         GLushort p = *(GLushort *)(buf + _x*2 + _y*pitch);              \
170         rgba[0] = (p << 3) & 0xf8;                                      \
171         rgba[1] = (p >> 3) & 0xfc;                                      \
172         rgba[2] = (p >> 8) & 0xf8;                                      \
173         rgba[3] = 0xff;                                                 \
174     } while (0)
175
176 #define TAG(x) tdfx##x##_BGR565
177 #define BYTESPERPIXEL 2
178 #include "spantmp.h"
179 #undef BYTESPERPIXEL
180 #endif
181
182
183 #undef LFB_MODE
184 #define LFB_MODE        GR_LFBWRITEMODE_888
185
186
187 /* 24 bit, RGB888 color spanline and pixel functions */
188 #undef INIT_MONO_PIXEL
189 #define INIT_MONO_PIXEL(p, color) \
190   p = TDFXPACKCOLOR888( color[0], color[1], color[2] )
191
192 #define WRITE_RGBA( _x, _y, r, g, b, a )                                \
193    *(GLuint *)(buf + _x*3 + _y*pitch) = ((b << 0) |                     \
194                                          (g << 8) |                     \
195                                          (r << 16))
196
197 #define WRITE_PIXEL( _x, _y, p )                                        \
198    *(GLuint *)(buf + _x*3 + _y*pitch) = p
199
200 #define READ_RGBA( rgba, _x, _y )                                       \
201 do {                                                                    \
202    GLuint p = *(GLuint *)(buf + _x*3 + _y*pitch);                       \
203    rgba[0] = (p >> 16) & 0xff;                                          \
204    rgba[1] = (p >> 8)  & 0xff;                                          \
205    rgba[2] = (p >> 0)  & 0xff;                                          \
206    rgba[3] = 0xff;                                                      \
207 } while (0)
208
209 #define TAG(x) tdfx##x##_RGB888
210 #define BYTESPERPIXEL 4
211 #include "spantmp.h"
212 #undef BYTESPERPIXEL
213
214
215 #undef LFB_MODE
216 #define LFB_MODE        GR_LFBWRITEMODE_8888
217
218
219 /* 32 bit, ARGB8888 color spanline and pixel functions */
220 #undef INIT_MONO_PIXEL
221 #define INIT_MONO_PIXEL(p, color) \
222   p = TDFXPACKCOLOR8888( color[0], color[1], color[2], color[3] )
223
224 #define WRITE_RGBA( _x, _y, r, g, b, a )                                \
225    *(GLuint *)(buf + _x*4 + _y*pitch) = ((b <<  0) |                    \
226                                          (g <<  8) |                    \
227                                          (r << 16) |                    \
228                                          (a << 24) )
229
230 #define WRITE_PIXEL( _x, _y, p )                                        \
231    *(GLuint *)(buf + _x*4 + _y*pitch) = p
232
233 #define READ_RGBA( rgba, _x, _y )                                       \
234 do {                                                                    \
235    GLuint p = *(GLuint *)(buf + _x*4 + _y*pitch);                       \
236    rgba[0] = (p >> 16) & 0xff;                                          \
237    rgba[1] = (p >>  8) & 0xff;                                          \
238    rgba[2] = (p >>  0) & 0xff;                                          \
239    rgba[3] = (p >> 24) & 0xff;                                          \
240 } while (0)
241
242 #define TAG(x) tdfx##x##_ARGB8888
243 #define BYTESPERPIXEL 4
244 #include "spantmp.h"
245 #undef BYTESPERPIXEL
246
247
248
249 /* ================================================================
250  * Old span functions below...
251  */
252
253
254 /*
255  * Examine the cliprects to generate an array of flags to indicate
256  * which pixels in a span are visible.  Note: (x,y) is a screen
257  * coordinate.
258  */
259 static void
260 generate_vismask(const tdfxContextPtr fxMesa, GLint x, GLint y, GLint n,
261                  GLubyte vismask[])
262 {
263    GLboolean initialized = GL_FALSE;
264    GLint i, j;
265
266    /* Ensure we clear the visual mask */
267    memset(vismask, 0, n);
268
269    /* turn on flags for all visible pixels */
270    for (i = 0; i < fxMesa->numClipRects; i++) {
271       const drm_clip_rect_t *rect = &fxMesa->pClipRects[i];
272
273       if (y >= rect->y1 && y < rect->y2) {
274          if (x >= rect->x1 && x + n <= rect->x2) {
275             /* common case, whole span inside cliprect */
276             memset(vismask, 1, n);
277             return;
278          }
279          if (x < rect->x2 && x + n >= rect->x1) {
280             /* some of the span is inside the rect */
281             GLint start, end;
282             if (!initialized) {
283                memset(vismask, 0, n);
284                initialized = GL_TRUE;
285             }
286             if (x < rect->x1)
287                start = rect->x1 - x;
288             else
289                start = 0;
290             if (x + n > rect->x2)
291                end = rect->x2 - x;
292             else
293                end = n;
294             assert(start >= 0);
295             assert(end <= n);
296             for (j = start; j < end; j++)
297                vismask[j] = 1;
298          }
299       }
300    }
301 }
302
303 /*
304  * Examine cliprects and determine if the given screen pixel is visible.
305  */
306 static GLboolean
307 visible_pixel(const tdfxContextPtr fxMesa, int scrX, int scrY)
308 {
309    int i;
310    for (i = 0; i < fxMesa->numClipRects; i++) {
311       const drm_clip_rect_t *rect = &fxMesa->pClipRects[i];
312       if (scrX >= rect->x1 &&
313           scrX < rect->x2 &&
314           scrY >= rect->y1 && scrY < rect->y2) return GL_TRUE;
315    }
316    return GL_FALSE;
317 }
318
319
320
321 /*
322  * Depth buffer read/write functions.
323  */
324 /*
325  * To read the frame buffer, we need to lock and unlock it.  The
326  * four macros {READ,WRITE}_FB_SPAN_{LOCK,UNLOCK}
327  * do this for us.
328  *
329  * Note that the lock must be matched with an unlock.  These
330  * macros include a spare curly brace, so they must
331  * be syntactically matched.
332  *
333  * Note, also, that you can't lock a buffer twice with different
334  * modes.  That is to say, you can't lock a buffer in both read
335  * and write modes.  The strideInBytes and LFB pointer will be
336  * the same with read and write locks, so you can use either.
337  * o The HW has different state for reads and writes, so
338  *   locking it twice may give screwy results.
339  * o The DRM won't let you lock twice.  It hangs.  This is probably
340  *   because of the LOCK_HARDWARE IN THE *_FB_SPAN_LOCK macros,
341  *   and could be eliminated with nonlocking lock routines.  But
342  *   what's the point after all.
343  */
344 #define READ_FB_SPAN_LOCK(fxMesa, info, target_buffer)              \
345   UNLOCK_HARDWARE(fxMesa);                                          \
346   LOCK_HARDWARE(fxMesa);                                            \
347   (info).size=sizeof(info);                                         \
348   if (fxMesa->Glide.grLfbLock(GR_LFB_READ_ONLY,                     \
349                 target_buffer,                                      \
350                 GR_LFBWRITEMODE_ANY,                                \
351                 GR_ORIGIN_UPPER_LEFT,                               \
352                 FXFALSE,                                            \
353                 &(info))) {
354
355 #define READ_FB_SPAN_UNLOCK(fxMesa, target_buffer)                  \
356     fxMesa->Glide.grLfbUnlock(GR_LFB_READ_ONLY, target_buffer);     \
357   } else {                                                          \
358     fprintf(stderr, "tdfxDriver: Can't get %s (%d) read lock\n",    \
359             (target_buffer == GR_BUFFER_BACKBUFFER)                 \
360                 ? "back buffer"                                     \
361             : ((target_buffer == GR_BUFFER_AUXBUFFER)               \
362                 ? "depth buffer"                                    \
363                : "unknown buffer"),                                 \
364             target_buffer);                                         \
365   }
366
367 #define WRITE_FB_SPAN_LOCK(fxMesa, info, target_buffer, write_mode) \
368   UNLOCK_HARDWARE(fxMesa);                                          \
369   LOCK_HARDWARE(fxMesa);                                            \
370   info.size=sizeof(info);                                           \
371   if (fxMesa->Glide.grLfbLock(GR_LFB_WRITE_ONLY,                    \
372                 target_buffer,                                      \
373                 write_mode,                                         \
374                 GR_ORIGIN_UPPER_LEFT,                               \
375                 FXFALSE,                                            \
376                 &info)) {
377
378 #define WRITE_FB_SPAN_UNLOCK(fxMesa, target_buffer)                 \
379     fxMesa->Glide.grLfbUnlock(GR_LFB_WRITE_ONLY, target_buffer);    \
380   } else {                                                          \
381     fprintf(stderr, "tdfxDriver: Can't get %s (%d) write lock\n",   \
382             (target_buffer == GR_BUFFER_BACKBUFFER)                 \
383                 ? "back buffer"                                     \
384             : ((target_buffer == GR_BUFFER_AUXBUFFER)               \
385                 ? "depth buffer"                                    \
386                : "unknown buffer"),                                 \
387             target_buffer);                                         \
388   }
389
390 /*
391  * Because the Linear Frame Buffer is not necessarily aligned
392  * with the depth buffer, we have to do some fiddling
393  * around to get the right addresses.
394  *
395  * Perhaps a picture is in order.  The Linear Frame Buffer
396  * looks like this:
397  *
398  *   |<----------------------info.strideInBytes------------->|
399  *   |<-----physicalStrideInBytes------->|
400  *   +-----------------------------------+xxxxxxxxxxxxxxxxxxx+
401  *   |                                   |                   |
402  *   |          Legal Memory             |  Forbidden Zone   |
403  *   |                                   |                   |
404  *   +-----------------------------------+xxxxxxxxxxxxxxxxxxx+
405  *
406  * You can only reliably read and write legal locations.  Reads
407  * and writes from the Forbidden Zone will return undefined values,
408  * and may cause segmentation faults.
409  *
410  * Now, the depth buffer may not end up in a location such each
411  * scan line is an LFB line.  For example, the depth buffer may
412  * look like this:
413  *
414  *    wrapped               ordinary.
415  *   +-----------------------------------+xxxxxxxxxxxxxxxxxxx+
416  *   |0000000000000000000000             |                   | back
417  *   |1111111111111111111111             |                   | buffer
418  *   |2222222222222222222222             |                   |
419  *   |4096b align. padxx00000000000000000|  Forbidden Zone   | depth
420  *   |0000              11111111111111111|                   | buffer
421  *   |1111              22222222222222222|                   |
422  *   |2222                               |                   |
423  *   +-----------------------------------+xxxxxxxxxxxxxxxxxxx+
424  * where each number is the scan line number.  We know it will
425  * be aligned on 128 byte boundaries, at least.  Aligning this
426  * on a scanline boundary causes the back and depth buffers to
427  * thrash in the SST1 cache.  (Note that the back buffer is always
428  * allocated at the beginning of LFB memory, and so it is always
429  * properly aligned with the LFB stride.)
430  *
431  * We call the beginning of the line (which is the rightmost
432  * part of the depth line in the picture above) the *ordinary* part
433  * of the scanline, and the end of the line (which is the
434  * leftmost part, one line below) the *wrapped* part of the scanline.
435  * a.) We need to know what x value to subtract from the screen
436  *     x coordinate to index into the wrapped part.
437  * b.) We also need to figure out if we need to read from the ordinary
438  *     part scan line, or from the wrapped part of the scan line.
439  *
440  * [ad a]
441  * The first wrapped x coordinate is that coordinate such that
442  *           depthBufferOffset&(info.strideInBytes) + x*elmentSize  {*}
443  *                            > physicalStrideInBytes
444  *     where depthBufferOffset is the LFB distance in bytes
445  *     from the back buffer to the depth buffer.  The expression
446  *           depthBufferOffset&(info.strideInBytes)
447  *     is then the offset (in bytes) from the beginining of (any)
448  *     depth buffer line to first element in the line.
449  * Simplifying inequation {*} above we see that x is the smallest
450  * value such that
451  *         x*elementSize > physicalStrideInBytes                      {**}
452  *                            - depthBufferOffset&(info.strideInBytes)
453  * Now, we know that both the summands on the right are multiples of
454  * 128, and elementSize <= 4, so if equality holds in {**}, x would
455  * be a multiple of 32.  Thus we can set x to
456  *         xwrapped = (physicalStrideInBytes
457  *                      - depthBufferOffset&(info.strideInBytes))/elementSize
458  *                      + 1
459  *
460  * [ad b]
461  * Question b is now simple.  We read from the wrapped scan line if
462  * x is greater than xwrapped.
463  */
464 #define TILE_WIDTH_IN_BYTES             128
465 #define TILE_WIDTH_IN_ZOXELS(bpz)       (TILE_WIDTH_IN_BYTES/(bpz))
466 #define TILE_HEIGHT_IN_LINES            32
467 typedef struct
468 {
469    void *lfbPtr;
470    void *lfbWrapPtr;
471    FxU32 LFBStrideInElts;
472    GLint firstWrappedX;
473 }
474 LFBParameters;
475
476 /*
477  * We need information about the back buffer.  Note that
478  * this function *cannot be called* while the aux buffer
479  * is locked, or the caller will hang.
480  *
481  * Only Glide knows the LFB address of the back and depth
482  * offsets.  The upper levels of Mesa know the depth offset,
483  * but that is not in LFB space, it is tiled memory space,
484  * and is not useable for us.
485  */
486 static void
487 GetBackBufferInfo(tdfxContextPtr fxMesa, GrLfbInfo_t * backBufferInfo)
488 {
489    READ_FB_SPAN_LOCK(fxMesa, *backBufferInfo, GR_BUFFER_BACKBUFFER);
490    READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_BACKBUFFER);
491 }
492
493 static void
494 GetFbParams(tdfxContextPtr fxMesa,
495             GrLfbInfo_t * info,
496             GrLfbInfo_t * backBufferInfo,
497             LFBParameters * ReadParamsp, FxU32 elementSize)
498 {
499    FxU32 physicalStrideInBytes, bufferOffset;
500    FxU32 strideInBytes = info->strideInBytes;
501    char *lfbPtr = (char *) (info->lfbPtr); /* For arithmetic, use char * */
502
503    /*
504     * These two come directly from the info structure.
505     */
506    ReadParamsp->lfbPtr = (void *) lfbPtr;
507    ReadParamsp->LFBStrideInElts = strideInBytes / elementSize;
508    /*
509     * Now, calculate the value of firstWrappedX.
510     *
511     * The physical stride is the screen width in bytes rounded up to
512     * the next highest multiple of 128 bytes.  Note that this fails
513     * when TILE_WIDTH_IN_BYTES is not a power of two.
514     *
515     * The buffer Offset is the distance between the beginning of
516     * the LFB space, which is the beginning of the back buffer,
517     * and the buffer we are gathering information about.
518     * We want to make this routine usable for operations on the
519     * back buffer, though we don't actually use it on the back
520     * buffer.  Note, then, that if bufferOffset == 0, the firstWrappedX
521     * is in the forbidden zone, and is therefore never reached.
522     *
523     * Note that if
524     *     physicalStrideInBytes
525     *             < bufferOffset&(info->strideInBytes-1)
526     * the buffer begins in the forbidden zone.  We assert for this.
527     */
528    bufferOffset = (FxU32)(lfbPtr - (char *) backBufferInfo->lfbPtr);
529    physicalStrideInBytes
530       = (fxMesa->screen_width * elementSize + TILE_WIDTH_IN_BYTES - 1)
531       & ~(TILE_WIDTH_IN_BYTES - 1);
532    assert(physicalStrideInBytes > (bufferOffset & (strideInBytes - 1)));
533    ReadParamsp->firstWrappedX
534       = (physicalStrideInBytes
535          - (bufferOffset & (strideInBytes - 1))) / elementSize;
536    /*
537     * This is the address of the next physical line.
538     */
539    ReadParamsp->lfbWrapPtr
540       = (void *) ((char *) backBufferInfo->lfbPtr
541                   + (bufferOffset & ~(strideInBytes - 1))
542                   + (TILE_HEIGHT_IN_LINES) * strideInBytes);
543 }
544
545 /*
546  * These macros fetch data from the frame buffer.  The type is
547  * the type of data we want to fetch.  It should match the type
548  * whose size was used with GetFbParams to fill in the structure
549  * in *ReadParamsp.  We have a macro to read the ordinary
550  * part, a second macro to read the wrapped part, and one which
551  * will do either.  When we are reading a span, we will know
552  * when the ordinary part ends, so there's no need to test for
553  * it.  However, when reading and writing pixels, we don't
554  * necessarily know.  I suppose it's a matter of taste whether
555  * it's better in the macro or in the call.
556  *
557  * Recall that x and y are screen coordinates.
558  */
559 #define GET_ORDINARY_FB_DATA(ReadParamsp, type, x, y)               \
560     (((type *)((ReadParamsp)->lfbPtr))                              \
561                  [(y) * ((ReadParamsp)->LFBStrideInElts)            \
562                    + (x)])
563 #define GET_WRAPPED_FB_DATA(ReadParamsp, type, x, y)                \
564     (((type *)((ReadParamsp)->lfbWrapPtr))                          \
565                  [((y)) * ((ReadParamsp)->LFBStrideInElts)          \
566                    + ((x) - (ReadParamsp)->firstWrappedX)])
567 #define GET_FB_DATA(ReadParamsp, type, x, y)                        \
568    (((x) < (ReadParamsp)->firstWrappedX)                            \
569         ? GET_ORDINARY_FB_DATA(ReadParamsp, type, x, y)             \
570         : GET_WRAPPED_FB_DATA(ReadParamsp, type, x, y))
571 #define PUT_ORDINARY_FB_DATA(ReadParamsp, type, x, y, value)              \
572     (GET_ORDINARY_FB_DATA(ReadParamsp, type, x, y) = (type)(value))
573 #define PUT_WRAPPED_FB_DATA(ReadParamsp, type, x, y, value)                \
574     (GET_WRAPPED_FB_DATA(ReadParamsp, type, x, y) = (type)(value))
575 #define PUT_FB_DATA(ReadParamsp, type, x, y, value)                 \
576     do {                                                            \
577         if ((x) < (ReadParamsp)->firstWrappedX)                     \
578             PUT_ORDINARY_FB_DATA(ReadParamsp, type, x, y, value);   \
579         else                                                        \
580             PUT_WRAPPED_FB_DATA(ReadParamsp, type, x, y, value);    \
581     } while (0)
582
583
584 static void
585 tdfxDDWriteDepthSpan(struct gl_context * ctx, struct gl_renderbuffer *rb,
586                      GLuint n, GLint x, GLint y, const void *values,
587                      const GLubyte mask[])
588 {
589    const GLuint *depth = (const GLuint *) values;
590    tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx;
591    GLint bottom = fxMesa->y_offset + fxMesa->height - 1;
592    GLuint depth_size = fxMesa->glCtx->Visual.depthBits;
593    GLuint stencil_size = fxMesa->glCtx->Visual.stencilBits;
594    GrLfbInfo_t info;
595    GLubyte visMask[MAX_WIDTH];
596
597    if (MESA_VERBOSE & VERBOSE_DRIVER) {
598       fprintf(stderr, "tdfxmesa: tdfxDDWriteDepthSpan(...)\n");
599    }
600
601    assert((depth_size == 16) || (depth_size == 24) || (depth_size == 32));
602    /*
603     * Convert x and y to screen coordinates.
604     */
605    x += fxMesa->x_offset;
606    y = bottom - y;
607    if (mask) {
608       GLint i;
609       GLushort d16;
610       GrLfbInfo_t backBufferInfo;
611
612       switch (depth_size) {
613       case 16:
614          GetBackBufferInfo(fxMesa, &backBufferInfo);
615          /*
616           * Note that the _LOCK macro adds a curly brace,
617           * and the UNLOCK macro removes it.
618           */
619          WRITE_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER,
620                             GR_LFBWRITEMODE_ANY);
621          generate_vismask(fxMesa, x, y, n, visMask);
622          {
623             LFBParameters ReadParams;
624             int wrappedPartStart;
625             GetFbParams(fxMesa, &info, &backBufferInfo,
626                         &ReadParams, sizeof(GLushort));
627             if (ReadParams.firstWrappedX <= x) {
628                wrappedPartStart = 0;
629             }
630             else if (n <= (ReadParams.firstWrappedX - x)) {
631                wrappedPartStart = n;
632             }
633             else {
634                wrappedPartStart = (ReadParams.firstWrappedX - x);
635             }
636             for (i = 0; i < wrappedPartStart; i++) {
637                if (mask[i] && visMask[i]) {
638                   d16 = depth[i];
639                   PUT_ORDINARY_FB_DATA(&ReadParams, GLushort, x + i, y, d16);
640                }
641             }
642             for (; i < n; i++) {
643                if (mask[i] && visMask[i]) {
644                   d16 = depth[i];
645                   PUT_WRAPPED_FB_DATA(&ReadParams, GLushort, x + i, y, d16);
646                }
647             }
648          }
649          WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
650          break;
651       case 24:
652       case 32:
653          GetBackBufferInfo(fxMesa, &backBufferInfo);
654          /*
655           * Note that the _LOCK macro adds a curly brace,
656           * and the UNLOCK macro removes it.
657           */
658          WRITE_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER,
659                             GR_LFBWRITEMODE_ANY);
660          generate_vismask(fxMesa, x, y, n, visMask);
661          {
662             LFBParameters ReadParams;
663             int wrappedPartStart;
664             GetFbParams(fxMesa, &info, &backBufferInfo,
665                         &ReadParams, sizeof(GLuint));
666             if (ReadParams.firstWrappedX <= x) {
667                wrappedPartStart = 0;
668             }
669             else if (n <= (ReadParams.firstWrappedX - x)) {
670                wrappedPartStart = n;
671             }
672             else {
673                wrappedPartStart = (ReadParams.firstWrappedX - x);
674             }
675             for (i = 0; i < wrappedPartStart; i++) {
676                GLuint d32;
677                if (mask[i] && visMask[i]) {
678                   if (stencil_size > 0) {
679                      d32 =
680                         GET_ORDINARY_FB_DATA(&ReadParams, GLuint,
681                                              x + i, y);
682                      d32 =
683                         (d32 & 0xFF000000) | (depth[i] & 0x00FFFFFF);
684                   }
685                   else {
686                      d32 = depth[i];
687                   }
688                   PUT_ORDINARY_FB_DATA(&ReadParams, GLuint, x + i, y, d32);
689                }
690             }
691             for (; i < n; i++) {
692                GLuint d32;
693                if (mask[i] && visMask[i]) {
694                   if (stencil_size > 0) {
695                      d32 =
696                         GET_WRAPPED_FB_DATA(&ReadParams, GLuint,
697                                             x + i, y);
698                      d32 =
699                         (d32 & 0xFF000000) | (depth[i] & 0x00FFFFFF);
700                   }
701                   else {
702                      d32 = depth[i];
703                   }
704                   PUT_WRAPPED_FB_DATA(&ReadParams, GLuint, x + i, y, d32);
705                }
706             }
707          }
708          WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
709          break;
710       }
711    }
712    else {
713       GLint i;
714       GLuint d32;
715       GLushort d16;
716       GrLfbInfo_t backBufferInfo;
717
718       switch (depth_size) {
719       case 16:
720          GetBackBufferInfo(fxMesa, &backBufferInfo);
721          /*
722           * Note that the _LOCK macro adds a curly brace,
723           * and the UNLOCK macro removes it.
724           */
725          WRITE_FB_SPAN_LOCK(fxMesa, info,
726                             GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY);
727          generate_vismask(fxMesa, x, y, n, visMask);
728          {
729             LFBParameters ReadParams;
730             GLuint wrappedPartStart;
731             GetFbParams(fxMesa, &info, &backBufferInfo,
732                         &ReadParams, sizeof(GLushort));
733             if (ReadParams.firstWrappedX <= x) {
734                wrappedPartStart = 0;
735             }
736             else if (n <= (ReadParams.firstWrappedX - x)) {
737                wrappedPartStart = n;
738             }
739             else {
740                wrappedPartStart = (ReadParams.firstWrappedX - x);
741             }
742             for (i = 0; i < wrappedPartStart; i++) {
743                if (visMask[i]) {
744                   d16 = depth[i];
745                   PUT_ORDINARY_FB_DATA(&ReadParams,
746                                        GLushort,
747                                        x + i, y,
748                                        d16);
749                }
750             }
751             for (; i < n; i++) {
752                if (visMask[i]) {
753                   d16 = depth[i];
754                   PUT_WRAPPED_FB_DATA(&ReadParams,
755                                       GLushort,
756                                       x + i, y,
757                                       d16);
758                }
759             }
760          }
761          WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
762          break;
763       case 24:
764       case 32:
765          GetBackBufferInfo(fxMesa, &backBufferInfo);
766          /*
767           * Note that the _LOCK macro adds a curly brace,
768           * and the UNLOCK macro removes it.
769           */
770          WRITE_FB_SPAN_LOCK(fxMesa, info,
771                             GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY);
772          generate_vismask(fxMesa, x, y, n, visMask);
773          {
774             LFBParameters ReadParams;
775             GLuint wrappedPartStart;
776
777             GetFbParams(fxMesa, &info, &backBufferInfo,
778                         &ReadParams, sizeof(GLuint));
779             if (ReadParams.firstWrappedX <= x) {
780                wrappedPartStart = 0;
781             }
782             else if (n <= (ReadParams.firstWrappedX - x)) {
783                wrappedPartStart = n;
784             }
785             else {
786                wrappedPartStart = (ReadParams.firstWrappedX - x);
787             }
788             for (i = 0; i < wrappedPartStart; i++) {
789                if (visMask[i]) {
790                   if (stencil_size > 0) {
791                      d32 = GET_ORDINARY_FB_DATA(&ReadParams, GLuint, x + i, y);
792                      d32 =
793                         (d32 & 0xFF000000) | (depth[i] & 0x00FFFFFF);
794                   }
795                   else {
796                      d32 = depth[i];
797                   }
798                   PUT_ORDINARY_FB_DATA(&ReadParams, GLuint, x + i, y, d32);
799                }
800             }
801             for (; i < n; i++) {
802                if (visMask[i]) {
803                   if (stencil_size > 0) {
804                      d32 = GET_WRAPPED_FB_DATA(&ReadParams, GLuint, x + i, y);
805                      d32 =
806                         (d32 & 0xFF000000) | (depth[i] & 0x00FFFFFF);
807                   }
808                   else {
809                      d32 = depth[i];
810                   }
811                   PUT_WRAPPED_FB_DATA(&ReadParams, GLuint, x + i, y, d32);
812                }
813             }
814          }
815          WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
816          break;
817       }
818    }
819 }
820
821 static void
822 tdfxDDWriteMonoDepthSpan(struct gl_context * ctx, struct gl_renderbuffer *rb,
823                          GLuint n, GLint x, GLint y, const void *value,
824                          const GLubyte mask[])
825 {
826    GLuint depthVal = *((GLuint *) value);
827    GLuint depths[MAX_WIDTH];
828    GLuint i;
829    for (i = 0; i < n; i++)
830       depths[i] = depthVal;
831    tdfxDDWriteDepthSpan(ctx, rb, n, x, y, depths, mask);
832 }
833
834
835 static void
836 tdfxDDReadDepthSpan(struct gl_context * ctx, struct gl_renderbuffer *rb,
837                     GLuint n, GLint x, GLint y, void *values)
838 {
839    GLuint *depth = (GLuint *) values;
840    tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx;
841    GLint bottom = fxMesa->height + fxMesa->y_offset - 1;
842    GLuint i;
843    GLuint depth_size = fxMesa->glCtx->Visual.depthBits;
844    GrLfbInfo_t info;
845
846    if (MESA_VERBOSE & VERBOSE_DRIVER) {
847       fprintf(stderr, "tdfxmesa: tdfxDDReadDepthSpan(...)\n");
848    }
849
850    /*
851     * Convert to screen coordinates.
852     */
853    x += fxMesa->x_offset;
854    y = bottom - y;
855    switch (depth_size) {
856    case 16:
857    {
858       LFBParameters ReadParams;
859       GrLfbInfo_t backBufferInfo;
860       int wrappedPartStart;
861       GetBackBufferInfo(fxMesa, &backBufferInfo);
862       /*
863        * Note that the _LOCK macro adds a curly brace,
864        * and the UNLOCK macro removes it.
865        */
866       READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER);
867       GetFbParams(fxMesa, &info, &backBufferInfo,
868                   &ReadParams, sizeof(GLushort));
869       if (ReadParams.firstWrappedX <= x) {
870          wrappedPartStart = 0;
871       }
872       else if (n <= (ReadParams.firstWrappedX - x)) {
873          wrappedPartStart = n;
874       }
875       else {
876          wrappedPartStart = (ReadParams.firstWrappedX - x);
877       }
878       /*
879        * Read the line.
880        */
881       for (i = 0; i < wrappedPartStart; i++) {
882          depth[i] =
883             GET_ORDINARY_FB_DATA(&ReadParams, GLushort, x + i, y);
884       }
885       for (; i < n; i++) {
886          depth[i] = GET_WRAPPED_FB_DATA(&ReadParams, GLushort,
887                                         x + i, y);
888       }
889       READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
890       break;
891    }
892    case 24:
893    case 32:
894    {
895       LFBParameters ReadParams;
896       GrLfbInfo_t backBufferInfo;
897       int wrappedPartStart;
898       GLuint stencil_size = fxMesa->glCtx->Visual.stencilBits;
899       GetBackBufferInfo(fxMesa, &backBufferInfo);
900       /*
901        * Note that the _LOCK macro adds a curly brace,
902        * and the UNLOCK macro removes it.
903        */
904       READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER);
905       GetFbParams(fxMesa, &info, &backBufferInfo,
906                   &ReadParams, sizeof(GLuint));
907       if (ReadParams.firstWrappedX <= x) {
908          wrappedPartStart = 0;
909       }
910       else if (n <= (ReadParams.firstWrappedX - x)) {
911          wrappedPartStart = n;
912       }
913       else {
914          wrappedPartStart = (ReadParams.firstWrappedX - x);
915       }
916       /*
917        * Read the line.
918        */
919       for (i = 0; i < wrappedPartStart; i++) {
920          const GLuint mask =
921             (stencil_size > 0) ? 0x00FFFFFF : 0xFFFFFFFF;
922          depth[i] =
923             GET_ORDINARY_FB_DATA(&ReadParams, GLuint, x + i, y);
924          depth[i] &= mask;
925       }
926       for (; i < n; i++) {
927          const GLuint mask =
928             (stencil_size > 0) ? 0x00FFFFFF : 0xFFFFFFFF;
929          depth[i] = GET_WRAPPED_FB_DATA(&ReadParams, GLuint, x + i, y);
930          depth[i] &= mask;
931       }
932       READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
933       break;
934    }
935    }
936 }
937
938
939 static void
940 tdfxDDWriteDepthPixels(struct gl_context * ctx, struct gl_renderbuffer *rb,
941                        GLuint n, const GLint x[], const GLint y[],
942                        const void *values, const GLubyte mask[])
943 {
944    const GLuint *depth = (const GLuint *) values;
945    tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx;
946    GLint bottom = fxMesa->height + fxMesa->y_offset - 1;
947    GLuint i;
948    GLushort d16;
949    GLuint d32;
950    GLuint depth_size = fxMesa->glCtx->Visual.depthBits;
951    GLuint stencil_size = fxMesa->glCtx->Visual.stencilBits;
952    GrLfbInfo_t info;
953    int xpos;
954    int ypos;
955    GrLfbInfo_t backBufferInfo;
956
957    if (MESA_VERBOSE & VERBOSE_DRIVER) {
958       fprintf(stderr, "tdfxmesa: tdfxDDWriteDepthPixels(...)\n");
959    }
960
961    switch (depth_size) {
962    case 16:
963       GetBackBufferInfo(fxMesa, &backBufferInfo);
964       /*
965        * Note that the _LOCK macro adds a curly brace,
966        * and the UNLOCK macro removes it.
967        */
968       WRITE_FB_SPAN_LOCK(fxMesa, info,
969                          GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY);
970       {
971          LFBParameters ReadParams;
972          GetFbParams(fxMesa, &info, &backBufferInfo,
973                      &ReadParams, sizeof(GLushort));
974          for (i = 0; i < n; i++) {
975             if ((!mask || mask[i]) && visible_pixel(fxMesa, x[i], y[i])) {
976                xpos = x[i] + fxMesa->x_offset;
977                ypos = bottom - y[i];
978                d16 = depth[i];
979                PUT_FB_DATA(&ReadParams, GLushort, xpos, ypos, d16);
980             }
981          }
982       }
983       WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
984       break;
985    case 24:
986    case 32:
987       GetBackBufferInfo(fxMesa, &backBufferInfo);
988       /*
989        * Note that the _LOCK macro adds a curly brace,
990        * and the UNLOCK macro removes it.
991        */
992       WRITE_FB_SPAN_LOCK(fxMesa, info,
993                          GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY);
994       {
995          LFBParameters ReadParams;
996          GetFbParams(fxMesa, &info, &backBufferInfo,
997                      &ReadParams, sizeof(GLuint));
998          for (i = 0; i < n; i++) {
999             if (!mask || mask[i]) {
1000                if (visible_pixel(fxMesa, x[i], y[i])) {
1001                   xpos = x[i] + fxMesa->x_offset;
1002                   ypos = bottom - y[i];
1003                   if (stencil_size > 0) {
1004                      d32 =
1005                         GET_FB_DATA(&ReadParams, GLuint, xpos, ypos);
1006                      d32 = (d32 & 0xFF000000) | (depth[i] & 0xFFFFFF);
1007                   }
1008                   else {
1009                      d32 = depth[i];
1010                   }
1011                   PUT_FB_DATA(&ReadParams, GLuint, xpos, ypos, d32);
1012                }
1013             }
1014          }
1015       }
1016       WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
1017       break;
1018    }
1019 }
1020
1021
1022 static void
1023 tdfxDDReadDepthPixels(struct gl_context * ctx, struct gl_renderbuffer *rb, GLuint n,
1024                       const GLint x[], const GLint y[], void *values)
1025 {
1026    GLuint *depth = (GLuint *) values;
1027    tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx;
1028    GLint bottom = fxMesa->height + fxMesa->y_offset - 1;
1029    GLuint i;
1030    GLuint depth_size = fxMesa->glCtx->Visual.depthBits;
1031    GLushort d16;
1032    int xpos;
1033    int ypos;
1034    GrLfbInfo_t info;
1035    GLuint stencil_size;
1036    GrLfbInfo_t backBufferInfo;
1037
1038    if (MESA_VERBOSE & VERBOSE_DRIVER) {
1039       fprintf(stderr, "tdfxmesa: tdfxDDReadDepthPixels(...)\n");
1040    }
1041
1042    assert((depth_size == 16) || (depth_size == 24) || (depth_size == 32));
1043    switch (depth_size) {
1044    case 16:
1045       GetBackBufferInfo(fxMesa, &backBufferInfo);
1046       /*
1047        * Note that the _LOCK macro adds a curly brace,
1048        * and the UNLOCK macro removes it.
1049        */
1050       READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER);
1051       {
1052          LFBParameters ReadParams;
1053          GetFbParams(fxMesa, &info, &backBufferInfo,
1054                      &ReadParams, sizeof(GLushort));
1055          for (i = 0; i < n; i++) {
1056             /*
1057              * Convert to screen coordinates.
1058              */
1059             xpos = x[i] + fxMesa->x_offset;
1060             ypos = bottom - y[i];
1061             d16 = GET_FB_DATA(&ReadParams, GLushort, xpos, ypos);
1062             depth[i] = d16;
1063          }
1064       }
1065       READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
1066       break;
1067    case 24:
1068    case 32:
1069       GetBackBufferInfo(fxMesa, &backBufferInfo);
1070       /*
1071        * Note that the _LOCK macro adds a curly brace,
1072        * and the UNLOCK macro removes it.
1073        */
1074       READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER);
1075       stencil_size = fxMesa->glCtx->Visual.stencilBits;
1076       {
1077          LFBParameters ReadParams;
1078          GetFbParams(fxMesa, &info, &backBufferInfo,
1079                      &ReadParams, sizeof(GLuint));
1080          for (i = 0; i < n; i++) {
1081             GLuint d32;
1082
1083             /*
1084              * Convert to screen coordinates.
1085              */
1086             xpos = x[i] + fxMesa->x_offset;
1087             ypos = bottom - y[i];
1088             d32 = GET_FB_DATA(&ReadParams, GLuint, xpos, ypos);
1089             if (stencil_size > 0) {
1090                d32 &= 0x00FFFFFF;
1091             }
1092             depth[i] = d32;
1093          }
1094       }
1095       READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
1096       break;
1097    default:
1098       assert(0);
1099    }
1100 }
1101
1102 /*
1103  * Stencil buffer read/write functions.
1104  */
1105 #define EXTRACT_S_FROM_ZS(zs) (((zs) >> 24) & 0xFF)
1106 #define EXTRACT_Z_FROM_ZS(zs) ((zs) & 0xffffff)
1107 #define BUILD_ZS(z, s)  (((s) << 24) | (z))
1108
1109 static void
1110 write_stencil_span(struct gl_context * ctx, struct gl_renderbuffer *rb,
1111                    GLuint n, GLint x, GLint y,
1112                    const void *values, const GLubyte mask[])
1113 {
1114    const GLubyte *stencil = (const GLubyte *) values;
1115    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
1116    GrLfbInfo_t info;
1117    GrLfbInfo_t backBufferInfo;
1118
1119    GetBackBufferInfo(fxMesa, &backBufferInfo);
1120    /*
1121     * Note that the _LOCK macro adds a curly brace,
1122     * and the UNLOCK macro removes it.
1123     */
1124    WRITE_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY);
1125    {
1126       const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
1127       const GLint winX = fxMesa->x_offset;
1128       const GLint scrX = winX + x;
1129       const GLint scrY = winY - y;
1130       LFBParameters ReadParams;
1131       GLubyte visMask[MAX_WIDTH];
1132       GLuint i;
1133       int wrappedPartStart;
1134
1135       GetFbParams(fxMesa, &info, &backBufferInfo, &ReadParams,
1136                   sizeof(GLuint));
1137       if (ReadParams.firstWrappedX <= x) {
1138          wrappedPartStart = 0;
1139       }
1140       else if (n <= (ReadParams.firstWrappedX - x)) {
1141          wrappedPartStart = n;
1142       }
1143       else {
1144          wrappedPartStart = (ReadParams.firstWrappedX - x);
1145       }
1146       generate_vismask(fxMesa, scrX, scrY, n, visMask);
1147       for (i = 0; i < wrappedPartStart; i++) {
1148          if (visMask[i] && (!mask || mask[i])) {
1149             GLuint z = GET_ORDINARY_FB_DATA(&ReadParams, GLuint,
1150                                             scrX + i, scrY) & 0x00FFFFFF;
1151             z |= (stencil[i] & 0xFF) << 24;
1152             PUT_ORDINARY_FB_DATA(&ReadParams, GLuint, scrX + i, scrY, z);
1153          }
1154       }
1155       for (; i < n; i++) {
1156          if (visMask[i] && (!mask || mask[i])) {
1157             GLuint z = GET_WRAPPED_FB_DATA(&ReadParams, GLuint,
1158                                            scrX + i, scrY) & 0x00FFFFFF;
1159             z |= (stencil[i] & 0xFF) << 24;
1160             PUT_WRAPPED_FB_DATA(&ReadParams, GLuint, scrX + i, scrY, z);
1161          }
1162       }
1163    }
1164    WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
1165 }
1166
1167
1168 static void
1169 write_mono_stencil_span(struct gl_context * ctx, struct gl_renderbuffer *rb,
1170                         GLuint n, GLint x, GLint y,
1171                         const void *value, const GLubyte mask[])
1172 {
1173    GLbyte stencilVal = *((GLbyte *) value);
1174    GLbyte stencils[MAX_WIDTH];
1175    GLuint i;
1176    for (i = 0; i < n; i++)
1177       stencils[i] = stencilVal;
1178    write_stencil_span(ctx, rb, n, x, y, stencils, mask);
1179 }
1180
1181
1182 static void
1183 read_stencil_span(struct gl_context * ctx, struct gl_renderbuffer *rb,
1184                   GLuint n, GLint x, GLint y,
1185                   void *values)
1186 {
1187    GLubyte *stencil = (GLubyte *) values;
1188    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
1189    GrLfbInfo_t info;
1190    GrLfbInfo_t backBufferInfo;
1191
1192    GetBackBufferInfo(fxMesa, &backBufferInfo);
1193    /*
1194     * Note that the _LOCK macro adds a curly brace,
1195     * and the UNLOCK macro removes it.
1196     */
1197    READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER);
1198    {
1199       const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
1200       const GLint winX = fxMesa->x_offset;
1201       GLuint i;
1202       LFBParameters ReadParams;
1203       int wrappedPartStart;
1204
1205       /*
1206        * Convert to screen coordinates.
1207        */
1208       x += winX;
1209       y = winY - y;
1210       GetFbParams(fxMesa, &info, &backBufferInfo, &ReadParams,
1211                   sizeof(GLuint));
1212       if (ReadParams.firstWrappedX <= x) {
1213          wrappedPartStart = 0;
1214       }
1215       else if (n <= (ReadParams.firstWrappedX - x)) {
1216          wrappedPartStart = n;
1217       }
1218       else {
1219          wrappedPartStart = (ReadParams.firstWrappedX - x);
1220       }
1221       for (i = 0; i < wrappedPartStart; i++) {
1222          stencil[i] = (GET_ORDINARY_FB_DATA(&ReadParams, GLuint,
1223                                             x + i, y) >> 24) & 0xFF;
1224       }
1225       for (; i < n; i++) {
1226          stencil[i] = (GET_WRAPPED_FB_DATA(&ReadParams, GLuint,
1227                                            x + i, y) >> 24) & 0xFF;
1228       }
1229    }
1230    READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
1231 }
1232
1233
1234 static void
1235 write_stencil_pixels(struct gl_context * ctx, struct gl_renderbuffer *rb,
1236                      GLuint n, const GLint x[], const GLint y[],
1237                      const void *values, const GLubyte mask[])
1238 {
1239    const GLubyte *stencil = (const GLubyte *) values;
1240    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
1241    GrLfbInfo_t info;
1242    GrLfbInfo_t backBufferInfo;
1243
1244    GetBackBufferInfo(fxMesa, &backBufferInfo);
1245    /*
1246     * Note that the _LOCK macro adds a curly brace,
1247     * and the UNLOCK macro removes it.
1248     */
1249    WRITE_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY);
1250    {
1251       const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
1252       const GLint winX = fxMesa->x_offset;
1253       LFBParameters ReadParams;
1254       GLuint i;
1255
1256       GetFbParams(fxMesa, &info, &backBufferInfo, &ReadParams,
1257                   sizeof(GLuint));
1258       for (i = 0; i < n; i++) {
1259          const GLint scrX = winX + x[i];
1260          const GLint scrY = winY - y[i];
1261          if ((!mask || mask[i]) && visible_pixel(fxMesa, scrX, scrY)) {
1262             GLuint z =
1263                GET_FB_DATA(&ReadParams, GLuint, scrX, scrY) & 0x00FFFFFF;
1264             z |= (stencil[i] & 0xFF) << 24;
1265             PUT_FB_DATA(&ReadParams, GLuint, scrX, scrY, z);
1266          }
1267       }
1268    }
1269    WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
1270 }
1271
1272
1273 static void
1274 read_stencil_pixels(struct gl_context * ctx, struct gl_renderbuffer *rb,
1275                     GLuint n, const GLint x[], const GLint y[],
1276                     void *values)
1277 {
1278    GLubyte *stencil = (GLubyte *) values;
1279    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
1280    GrLfbInfo_t info;
1281    GrLfbInfo_t backBufferInfo;
1282
1283    GetBackBufferInfo(fxMesa, &backBufferInfo);
1284    /*
1285     * Note that the _LOCK macro adds a curly brace,
1286     * and the UNLOCK macro removes it.
1287     */
1288    READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER);
1289    {
1290       const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
1291       const GLint winX = fxMesa->x_offset;
1292       GLuint i;
1293       LFBParameters ReadParams;
1294
1295       GetFbParams(fxMesa, &info, &backBufferInfo, &ReadParams,
1296                   sizeof(GLuint));
1297       for (i = 0; i < n; i++) {
1298          const GLint scrX = winX + x[i];
1299          const GLint scrY = winY - y[i];
1300          stencil[i] =
1301             (GET_FB_DATA(&ReadParams, GLuint, scrX, scrY) >> 24) & 0xFF;
1302       }
1303    }
1304    READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER);
1305 }
1306
1307 #define VISUAL_EQUALS_RGBA(vis, r, g, b, a)        \
1308    ((vis.redBits == r) &&                         \
1309     (vis.greenBits == g) &&                       \
1310     (vis.blueBits == b) &&                        \
1311     (vis.alphaBits == a))
1312
1313
1314
1315
1316 /**********************************************************************/
1317 /*                    Locking for swrast                              */
1318 /**********************************************************************/
1319
1320
1321 static void tdfxSpanRenderStart( struct gl_context *ctx )
1322 {
1323    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
1324    LOCK_HARDWARE(fxMesa);
1325 }
1326
1327 static void tdfxSpanRenderFinish( struct gl_context *ctx )
1328 {
1329    tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
1330    _swrast_flush( ctx );
1331    UNLOCK_HARDWARE(fxMesa);
1332 }
1333
1334 /**********************************************************************/
1335 /*                    Initialize swrast device driver                 */
1336 /**********************************************************************/
1337
1338 void tdfxDDInitSpanFuncs( struct gl_context *ctx )
1339 {
1340    struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference( ctx );
1341    swdd->SpanRenderStart          = tdfxSpanRenderStart;
1342    swdd->SpanRenderFinish         = tdfxSpanRenderFinish; 
1343 }
1344
1345
1346
1347 /**
1348  * Plug in the Get/Put routines for the given driRenderbuffer.
1349  */
1350 void
1351 tdfxSetSpanFunctions(driRenderbuffer *drb, const struct gl_config *vis)
1352 {
1353    if (drb->Base.InternalFormat == GL_RGBA) {
1354       if (vis->redBits == 5 && vis->greenBits == 6 && vis->blueBits == 5) {
1355          tdfxInitPointers_RGB565(&drb->Base);
1356       }
1357       else if (vis->redBits == 8 && vis->greenBits == 8
1358                && vis->blueBits == 8 && vis->alphaBits == 0) {
1359          tdfxInitPointers_RGB888(&drb->Base);
1360       }
1361       else if (vis->redBits == 8 && vis->greenBits == 8
1362                && vis->blueBits == 8 && vis->alphaBits == 8) {
1363          tdfxInitPointers_ARGB8888(&drb->Base);
1364       }
1365       else {
1366          _mesa_problem(NULL, "problem in tdfxSetSpanFunctions");
1367       }
1368    }
1369    else if (drb->Base.InternalFormat == GL_DEPTH_COMPONENT16 ||
1370             drb->Base.InternalFormat == GL_DEPTH_COMPONENT24) {
1371       drb->Base.GetRow        = tdfxDDReadDepthSpan;
1372       drb->Base.GetValues     = tdfxDDReadDepthPixels;
1373       drb->Base.PutRow        = tdfxDDWriteDepthSpan;
1374       drb->Base.PutMonoRow    = tdfxDDWriteMonoDepthSpan;
1375       drb->Base.PutValues     = tdfxDDWriteDepthPixels;
1376       drb->Base.PutMonoValues = NULL;
1377    }
1378    else if (drb->Base.InternalFormat == GL_STENCIL_INDEX8_EXT) {
1379       drb->Base.GetRow        = read_stencil_span;
1380       drb->Base.GetValues     = read_stencil_pixels;
1381       drb->Base.PutRow        = write_stencil_span;
1382       drb->Base.PutMonoRow    = write_mono_stencil_span;
1383       drb->Base.PutValues     = write_stencil_pixels;
1384       drb->Base.PutMonoValues = NULL;
1385    }
1386 }