s_context.c revision a6c423d95663cfd8601cf84e10e8e1b12fa6ef15
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.1
4 *
5 * Copyright (C) 1999-2004  Brian Paul   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 shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Keith Whitwell <keith@tungstengraphics.com>
26 *    Brian Paul
27 */
28
29#include "imports.h"
30#include "bufferobj.h"
31#include "context.h"
32#include "colormac.h"
33#include "mtypes.h"
34#include "program.h"
35#include "texobj.h"
36#include "nvfragprog.h"
37
38#include "swrast.h"
39#include "s_blend.h"
40#include "s_context.h"
41#include "s_lines.h"
42#include "s_points.h"
43#include "s_span.h"
44#include "s_triangle.h"
45#include "s_texture.h"
46
47
48/**
49 * Recompute the value of swrast->_RasterMask, etc. according to
50 * the current context.  The _RasterMask field can be easily tested by
51 * drivers to determine certain basic GL state (does the primitive need
52 * stenciling, logic-op, fog, etc?).
53 */
54static void
55_swrast_update_rasterflags( GLcontext *ctx )
56{
57   GLuint rasterMask = 0;
58
59   if (ctx->Color.AlphaEnabled)           rasterMask |= ALPHATEST_BIT;
60   if (ctx->Color.BlendEnabled)           rasterMask |= BLEND_BIT;
61   if (ctx->Depth.Test)                   rasterMask |= DEPTH_BIT;
62   if (ctx->Fog.Enabled)                  rasterMask |= FOG_BIT;
63   if (ctx->Scissor.Enabled)              rasterMask |= CLIP_BIT;
64   if (ctx->Stencil.Enabled)              rasterMask |= STENCIL_BIT;
65   if (ctx->Visual.rgbMode) {
66      const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
67      if (colorMask != 0xffffffff)        rasterMask |= MASKING_BIT;
68      if (ctx->Color._LogicOpEnabled)     rasterMask |= LOGIC_OP_BIT;
69      if (ctx->Texture._EnabledUnits)     rasterMask |= TEXTURE_BIT;
70   }
71   else {
72      if (ctx->Color.IndexMask != 0xffffffff) rasterMask |= MASKING_BIT;
73      if (ctx->Color.IndexLogicOpEnabled)     rasterMask |= LOGIC_OP_BIT;
74   }
75
76   if (ctx->DrawBuffer->UseSoftwareAlphaBuffers
77       && ctx->Color.ColorMask[ACOMP]
78       && ctx->Color.DrawBuffer != GL_NONE)
79      rasterMask |= ALPHABUF_BIT;
80
81   if (   ctx->Viewport.X < 0
82       || ctx->Viewport.X + ctx->Viewport.Width > (GLint) ctx->DrawBuffer->Width
83       || ctx->Viewport.Y < 0
84       || ctx->Viewport.Y + ctx->Viewport.Height > (GLint) ctx->DrawBuffer->Height) {
85      rasterMask |= CLIP_BIT;
86   }
87
88   if (ctx->Depth.OcclusionTest || ctx->Occlusion.Active)
89      rasterMask |= OCCLUSION_BIT;
90
91
92   /* If we're not drawing to exactly one color buffer set the
93    * MULTI_DRAW_BIT flag.  Also set it if we're drawing to no
94    * buffers or the RGBA or CI mask disables all writes.
95    */
96   if (_mesa_bitcount(ctx->Color._DrawDestMask) != 1) {
97      /* more than one color buffer designated for writing (or zero buffers) */
98      rasterMask |= MULTI_DRAW_BIT;
99   }
100   else if (ctx->Visual.rgbMode && *((GLuint *) ctx->Color.ColorMask) == 0) {
101      rasterMask |= MULTI_DRAW_BIT; /* all RGBA channels disabled */
102   }
103   else if (!ctx->Visual.rgbMode && ctx->Color.IndexMask==0) {
104      rasterMask |= MULTI_DRAW_BIT; /* all color index bits disabled */
105   }
106
107   if (ctx->FragmentProgram._Enabled) {
108      rasterMask |= FRAGPROG_BIT;
109   }
110
111   SWRAST_CONTEXT(ctx)->_RasterMask = rasterMask;
112}
113
114
115/**
116 * Examine polycon culls tate to compute the _BackfaceSign field.
117 * _BackfaceSign will be 0 if no culling, -1 if culling back-faces,
118 * and 1 if culling front-faces.  The Polygon FrontFace state also
119 * factors in.
120 */
121static void
122_swrast_update_polygon( GLcontext *ctx )
123{
124   GLfloat backface_sign = 1;
125
126   if (ctx->Polygon.CullFlag) {
127      backface_sign = 1;
128      switch(ctx->Polygon.CullFaceMode) {
129      case GL_BACK:
130	 if(ctx->Polygon.FrontFace==GL_CCW)
131	    backface_sign = -1;
132	 break;
133      case GL_FRONT:
134	 if(ctx->Polygon.FrontFace!=GL_CCW)
135	    backface_sign = -1;
136	 break;
137      default:
138      case GL_FRONT_AND_BACK:
139	 backface_sign = 0;
140	 break;
141      }
142   }
143   else {
144      backface_sign = 0;
145   }
146
147   SWRAST_CONTEXT(ctx)->_BackfaceSign = backface_sign;
148}
149
150
151/**
152 * Update the _PreferPixelFog field to indicate if we need to compute
153 * fog factors per-fragment.
154 */
155static void
156_swrast_update_fog_hint( GLcontext *ctx )
157{
158   SWcontext *swrast = SWRAST_CONTEXT(ctx);
159   swrast->_PreferPixelFog = (!swrast->AllowVertexFog ||
160                              ctx->FragmentProgram._Enabled ||
161			      (ctx->Hint.Fog == GL_NICEST &&
162			       swrast->AllowPixelFog));
163}
164
165
166
167/**
168 * Update the swrast->_AnyTextureCombine flag.
169 */
170static void
171_swrast_update_texture_env( GLcontext *ctx )
172{
173   SWcontext *swrast = SWRAST_CONTEXT(ctx);
174   GLuint i;
175   swrast->_AnyTextureCombine = GL_FALSE;
176   for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
177      if (ctx->Texture.Unit[i].EnvMode == GL_COMBINE_EXT ||
178          ctx->Texture.Unit[i].EnvMode == GL_COMBINE4_NV) {
179         swrast->_AnyTextureCombine = GL_TRUE;
180         return;
181      }
182   }
183}
184
185
186/**
187 * Update swrast->_FogColor and swrast->_FogEnable values.
188 */
189static void
190_swrast_update_fog_state( GLcontext *ctx )
191{
192   SWcontext *swrast = SWRAST_CONTEXT(ctx);
193
194   /* convert fog color to GLchan values */
195   CLAMPED_FLOAT_TO_CHAN(swrast->_FogColor[RCOMP], ctx->Fog.Color[RCOMP]);
196   CLAMPED_FLOAT_TO_CHAN(swrast->_FogColor[GCOMP], ctx->Fog.Color[GCOMP]);
197   CLAMPED_FLOAT_TO_CHAN(swrast->_FogColor[BCOMP], ctx->Fog.Color[BCOMP]);
198
199   /* determine if fog is needed */
200   swrast->_FogEnabled = GL_FALSE;
201   if (ctx->Fog.Enabled) {
202      swrast->_FogEnabled = GL_TRUE;
203   }
204   else if (ctx->FragmentProgram._Enabled &&
205        ctx->FragmentProgram.Current->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
206      const struct fragment_program *p;
207      p = (struct fragment_program *) ctx->FragmentProgram.Current;
208      if (p->FogOption != GL_NONE) {
209         swrast->_FogEnabled = GL_TRUE;
210      }
211   }
212}
213
214
215/**
216 * Update state for running fragment programs.  Basically, load the
217 * program parameters with current state values.
218 */
219static void
220_swrast_update_fragment_program( GLcontext *ctx )
221{
222   if (ctx->FragmentProgram._Enabled) {
223      struct fragment_program *program = ctx->FragmentProgram.Current;
224      _mesa_load_state_parameters(ctx, program->Parameters);
225   }
226}
227
228
229
230#define _SWRAST_NEW_DERIVED (_SWRAST_NEW_RASTERMASK |	\
231			     _NEW_TEXTURE |		\
232			     _NEW_HINT |		\
233			     _NEW_POLYGON )
234
235/* State referenced by _swrast_choose_triangle, _swrast_choose_line.
236 */
237#define _SWRAST_NEW_TRIANGLE (_SWRAST_NEW_DERIVED |		\
238			      _NEW_RENDERMODE|			\
239                              _NEW_POLYGON|			\
240                              _NEW_DEPTH|			\
241                              _NEW_STENCIL|			\
242                              _NEW_COLOR|			\
243                              _NEW_TEXTURE|			\
244                              _SWRAST_NEW_RASTERMASK|		\
245                              _NEW_LIGHT|			\
246                              _NEW_FOG |			\
247			      _DD_NEW_SEPARATE_SPECULAR)
248
249#define _SWRAST_NEW_LINE (_SWRAST_NEW_DERIVED |		\
250			  _NEW_RENDERMODE|		\
251                          _NEW_LINE|			\
252                          _NEW_TEXTURE|			\
253                          _NEW_LIGHT|			\
254                          _NEW_FOG|			\
255                          _NEW_DEPTH |			\
256                          _DD_NEW_SEPARATE_SPECULAR)
257
258#define _SWRAST_NEW_POINT (_SWRAST_NEW_DERIVED |	\
259			   _NEW_RENDERMODE |		\
260			   _NEW_POINT |			\
261			   _NEW_TEXTURE |		\
262			   _NEW_LIGHT |			\
263			   _NEW_FOG |			\
264                           _DD_NEW_SEPARATE_SPECULAR)
265
266#define _SWRAST_NEW_TEXTURE_SAMPLE_FUNC _NEW_TEXTURE
267
268#define _SWRAST_NEW_TEXTURE_ENV_MODE _NEW_TEXTURE
269
270#define _SWRAST_NEW_BLEND_FUNC _NEW_COLOR
271
272
273
274/**
275 * Stub for swrast->Triangle to select a true triangle function
276 * after a state change.
277 */
278static void
279_swrast_validate_triangle( GLcontext *ctx,
280			   const SWvertex *v0,
281                           const SWvertex *v1,
282                           const SWvertex *v2 )
283{
284   SWcontext *swrast = SWRAST_CONTEXT(ctx);
285
286   _swrast_validate_derived( ctx );
287   swrast->choose_triangle( ctx );
288
289   if (ctx->Texture._EnabledUnits == 0
290       && NEED_SECONDARY_COLOR(ctx)
291       && !ctx->FragmentProgram._Enabled) {
292      /* separate specular color, but no texture */
293      swrast->SpecTriangle = swrast->Triangle;
294      swrast->Triangle = _swrast_add_spec_terms_triangle;
295   }
296
297   swrast->Triangle( ctx, v0, v1, v2 );
298}
299
300/**
301 * Called via swrast->Line.  Examine current GL state and choose a software
302 * line routine.  Then call it.
303 */
304static void
305_swrast_validate_line( GLcontext *ctx, const SWvertex *v0, const SWvertex *v1 )
306{
307   SWcontext *swrast = SWRAST_CONTEXT(ctx);
308
309   _swrast_validate_derived( ctx );
310   swrast->choose_line( ctx );
311
312   if (ctx->Texture._EnabledUnits == 0
313       && NEED_SECONDARY_COLOR(ctx)
314       && !ctx->FragmentProgram._Enabled) {
315      swrast->SpecLine = swrast->Line;
316      swrast->Line = _swrast_add_spec_terms_line;
317   }
318
319
320   swrast->Line( ctx, v0, v1 );
321}
322
323/**
324 * Called via swrast->Point.  Examine current GL state and choose a software
325 * point routine.  Then call it.
326 */
327static void
328_swrast_validate_point( GLcontext *ctx, const SWvertex *v0 )
329{
330   SWcontext *swrast = SWRAST_CONTEXT(ctx);
331
332   _swrast_validate_derived( ctx );
333   swrast->choose_point( ctx );
334
335   if (ctx->Texture._EnabledUnits == 0
336       && NEED_SECONDARY_COLOR(ctx)
337       && !ctx->FragmentProgram._Enabled) {
338      swrast->SpecPoint = swrast->Point;
339      swrast->Point = _swrast_add_spec_terms_point;
340   }
341
342   swrast->Point( ctx, v0 );
343}
344
345
346/**
347 * Called via swrast->BlendFunc.  Examine GL state to choose a blending
348 * function, then call it.
349 */
350static void _ASMAPI
351_swrast_validate_blend_func( GLcontext *ctx, GLuint n,
352			     const GLubyte mask[],
353			     GLchan src[][4],
354			     CONST GLchan dst[][4] )
355{
356   SWcontext *swrast = SWRAST_CONTEXT(ctx);
357
358   _swrast_validate_derived( ctx );
359   _swrast_choose_blend_func( ctx );
360
361   swrast->BlendFunc( ctx, n, mask, src, dst );
362}
363
364
365/**
366 * Called via the swrast->TextureSample[i] function pointer.
367 * Basically, given a texture object, an array of texture coords
368 * and an array of level-of-detail values, return an array of colors.
369 * In this case, determine the correct texture sampling routine
370 * (depending on filter mode, texture dimensions, etc) then call the
371 * sampler routine.
372 */
373static void
374_swrast_validate_texture_sample( GLcontext *ctx, GLuint texUnit,
375				 const struct gl_texture_object *tObj,
376				 GLuint n, const GLfloat texcoords[][4],
377				 const GLfloat lambda[], GLchan rgba[][4] )
378{
379   SWcontext *swrast = SWRAST_CONTEXT(ctx);
380
381   _swrast_validate_derived( ctx );
382
383   /* Compute min/mag filter threshold */
384   if (tObj && tObj->MinFilter != tObj->MagFilter) {
385      if (tObj->MagFilter == GL_LINEAR
386          && (tObj->MinFilter == GL_NEAREST_MIPMAP_NEAREST ||
387              tObj->MinFilter == GL_NEAREST_MIPMAP_LINEAR)) {
388         swrast->_MinMagThresh[texUnit] = 0.5F;
389      }
390      else {
391         swrast->_MinMagThresh[texUnit] = 0.0F;
392      }
393   }
394
395   swrast->TextureSample[texUnit] =
396      _swrast_choose_texture_sample_func( ctx, tObj );
397
398   swrast->TextureSample[texUnit]( ctx, texUnit, tObj, n, texcoords,
399                                   lambda, rgba );
400}
401
402
403static void
404_swrast_sleep( GLcontext *ctx, GLuint new_state )
405{
406   (void) ctx; (void) new_state;
407}
408
409
410static void
411_swrast_invalidate_state( GLcontext *ctx, GLuint new_state )
412{
413   SWcontext *swrast = SWRAST_CONTEXT(ctx);
414   GLuint i;
415
416   swrast->NewState |= new_state;
417
418   /* After 10 statechanges without any swrast functions being called,
419    * put the module to sleep.
420    */
421   if (++swrast->StateChanges > 10) {
422      swrast->InvalidateState = _swrast_sleep;
423      swrast->NewState = ~0;
424      new_state = ~0;
425   }
426
427   if (new_state & swrast->invalidate_triangle)
428      swrast->Triangle = _swrast_validate_triangle;
429
430   if (new_state & swrast->invalidate_line)
431      swrast->Line = _swrast_validate_line;
432
433   if (new_state & swrast->invalidate_point)
434      swrast->Point = _swrast_validate_point;
435
436   if (new_state & _SWRAST_NEW_BLEND_FUNC)
437      swrast->BlendFunc = _swrast_validate_blend_func;
438
439   if (new_state & _SWRAST_NEW_TEXTURE_SAMPLE_FUNC)
440      for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
441	 swrast->TextureSample[i] = _swrast_validate_texture_sample;
442
443   /* Debug checks */
444   if (ctx->Visual.rgbMode) {
445      ASSERT(swrast->Driver.WriteRGBASpan);
446      ASSERT(swrast->Driver.WriteRGBSpan);
447      ASSERT(swrast->Driver.WriteMonoRGBASpan);
448      ASSERT(swrast->Driver.WriteRGBAPixels);
449      ASSERT(swrast->Driver.WriteMonoRGBAPixels);
450      ASSERT(swrast->Driver.ReadRGBASpan);
451      ASSERT(swrast->Driver.ReadRGBAPixels);
452   }
453   else {
454      ASSERT(swrast->Driver.WriteCI32Span);
455      ASSERT(swrast->Driver.WriteCI8Span);
456      ASSERT(swrast->Driver.WriteMonoCISpan);
457      ASSERT(swrast->Driver.WriteCI32Pixels);
458      ASSERT(swrast->Driver.WriteMonoCIPixels);
459      ASSERT(swrast->Driver.ReadCI32Span);
460      ASSERT(swrast->Driver.ReadCI32Pixels);
461   }
462}
463
464
465void
466_swrast_validate_derived( GLcontext *ctx )
467{
468   SWcontext *swrast = SWRAST_CONTEXT(ctx);
469
470   if (swrast->NewState) {
471      if (swrast->NewState & _SWRAST_NEW_RASTERMASK)
472 	 _swrast_update_rasterflags( ctx );
473
474      if (swrast->NewState & _NEW_POLYGON)
475	 _swrast_update_polygon( ctx );
476
477      if (swrast->NewState & (_NEW_HINT | _NEW_PROGRAM))
478	 _swrast_update_fog_hint( ctx );
479
480      if (swrast->NewState & _SWRAST_NEW_TEXTURE_ENV_MODE)
481	 _swrast_update_texture_env( ctx );
482
483      if (swrast->NewState & _NEW_FOG)
484         _swrast_update_fog_state( ctx );
485
486      if (swrast->NewState & _NEW_PROGRAM)
487	 _swrast_update_fragment_program( ctx );
488
489      swrast->NewState = 0;
490      swrast->StateChanges = 0;
491      swrast->InvalidateState = _swrast_invalidate_state;
492   }
493}
494
495#define SWRAST_DEBUG 0
496
497/* Public entrypoints:  See also s_accum.c, s_bitmap.c, etc.
498 */
499void
500_swrast_Quad( GLcontext *ctx,
501	      const SWvertex *v0, const SWvertex *v1,
502              const SWvertex *v2, const SWvertex *v3 )
503{
504   if (SWRAST_DEBUG) {
505      _mesa_debug(ctx, "_swrast_Quad\n");
506      _swrast_print_vertex( ctx, v0 );
507      _swrast_print_vertex( ctx, v1 );
508      _swrast_print_vertex( ctx, v2 );
509      _swrast_print_vertex( ctx, v3 );
510   }
511   SWRAST_CONTEXT(ctx)->Triangle( ctx, v0, v1, v3 );
512   SWRAST_CONTEXT(ctx)->Triangle( ctx, v1, v2, v3 );
513}
514
515void
516_swrast_Triangle( GLcontext *ctx, const SWvertex *v0,
517                  const SWvertex *v1, const SWvertex *v2 )
518{
519   if (SWRAST_DEBUG) {
520      _mesa_debug(ctx, "_swrast_Triangle\n");
521      _swrast_print_vertex( ctx, v0 );
522      _swrast_print_vertex( ctx, v1 );
523      _swrast_print_vertex( ctx, v2 );
524   }
525   SWRAST_CONTEXT(ctx)->Triangle( ctx, v0, v1, v2 );
526}
527
528void
529_swrast_Line( GLcontext *ctx, const SWvertex *v0, const SWvertex *v1 )
530{
531   if (SWRAST_DEBUG) {
532      _mesa_debug(ctx, "_swrast_Line\n");
533      _swrast_print_vertex( ctx, v0 );
534      _swrast_print_vertex( ctx, v1 );
535   }
536   SWRAST_CONTEXT(ctx)->Line( ctx, v0, v1 );
537}
538
539void
540_swrast_Point( GLcontext *ctx, const SWvertex *v0 )
541{
542   if (SWRAST_DEBUG) {
543      _mesa_debug(ctx, "_swrast_Point\n");
544      _swrast_print_vertex( ctx, v0 );
545   }
546   SWRAST_CONTEXT(ctx)->Point( ctx, v0 );
547}
548
549void
550_swrast_InvalidateState( GLcontext *ctx, GLuint new_state )
551{
552   if (SWRAST_DEBUG) {
553      _mesa_debug(ctx, "_swrast_InvalidateState\n");
554   }
555   SWRAST_CONTEXT(ctx)->InvalidateState( ctx, new_state );
556}
557
558void
559_swrast_ResetLineStipple( GLcontext *ctx )
560{
561   if (SWRAST_DEBUG) {
562      _mesa_debug(ctx, "_swrast_ResetLineStipple\n");
563   }
564   SWRAST_CONTEXT(ctx)->StippleCounter = 0;
565}
566
567void
568_swrast_allow_vertex_fog( GLcontext *ctx, GLboolean value )
569{
570   if (SWRAST_DEBUG) {
571      _mesa_debug(ctx, "_swrast_allow_vertex_fog %d\n", value);
572   }
573   SWRAST_CONTEXT(ctx)->InvalidateState( ctx, _NEW_HINT );
574   SWRAST_CONTEXT(ctx)->AllowVertexFog = value;
575}
576
577void
578_swrast_allow_pixel_fog( GLcontext *ctx, GLboolean value )
579{
580   if (SWRAST_DEBUG) {
581      _mesa_debug(ctx, "_swrast_allow_pixel_fog %d\n", value);
582   }
583   SWRAST_CONTEXT(ctx)->InvalidateState( ctx, _NEW_HINT );
584   SWRAST_CONTEXT(ctx)->AllowPixelFog = value;
585}
586
587
588GLboolean
589_swrast_CreateContext( GLcontext *ctx )
590{
591   GLuint i;
592   SWcontext *swrast = (SWcontext *)CALLOC(sizeof(SWcontext));
593
594   if (SWRAST_DEBUG) {
595      _mesa_debug(ctx, "_swrast_CreateContext\n");
596   }
597
598   if (!swrast)
599      return GL_FALSE;
600
601   swrast->NewState = ~0;
602
603   swrast->choose_point = _swrast_choose_point;
604   swrast->choose_line = _swrast_choose_line;
605   swrast->choose_triangle = _swrast_choose_triangle;
606
607   swrast->invalidate_point = _SWRAST_NEW_POINT;
608   swrast->invalidate_line = _SWRAST_NEW_LINE;
609   swrast->invalidate_triangle = _SWRAST_NEW_TRIANGLE;
610
611   swrast->Point = _swrast_validate_point;
612   swrast->Line = _swrast_validate_line;
613   swrast->Triangle = _swrast_validate_triangle;
614   swrast->InvalidateState = _swrast_sleep;
615   swrast->BlendFunc = _swrast_validate_blend_func;
616
617   swrast->AllowVertexFog = GL_TRUE;
618   swrast->AllowPixelFog = GL_TRUE;
619
620   if (ctx->Visual.doubleBufferMode)
621      swrast->CurrentBufferBit = DD_BACK_LEFT_BIT;
622   else
623      swrast->CurrentBufferBit = DD_FRONT_LEFT_BIT;
624
625   /* Optimized Accum buffer */
626   swrast->_IntegerAccumMode = GL_TRUE;
627   swrast->_IntegerAccumScaler = 0.0;
628
629   for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
630      swrast->TextureSample[i] = _swrast_validate_texture_sample;
631
632   swrast->SpanArrays = MALLOC_STRUCT(span_arrays);
633   if (!swrast->SpanArrays) {
634      FREE(swrast);
635      return GL_FALSE;
636   }
637
638   /* init point span buffer */
639   swrast->PointSpan.primitive = GL_POINT;
640   swrast->PointSpan.start = 0;
641   swrast->PointSpan.end = 0;
642   swrast->PointSpan.facing = 0;
643   swrast->PointSpan.array = swrast->SpanArrays;
644
645   assert(ctx->Const.MaxTextureUnits > 0);
646   assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_UNITS);
647
648   swrast->TexelBuffer = (GLchan *) MALLOC(ctx->Const.MaxTextureUnits *
649                                           MAX_WIDTH * 4 * sizeof(GLchan));
650   if (!swrast->TexelBuffer) {
651      FREE(swrast->SpanArrays);
652      FREE(swrast);
653      return GL_FALSE;
654   }
655
656   ctx->swrast_context = swrast;
657
658   return GL_TRUE;
659}
660
661void
662_swrast_DestroyContext( GLcontext *ctx )
663{
664   SWcontext *swrast = SWRAST_CONTEXT(ctx);
665
666   if (SWRAST_DEBUG) {
667      _mesa_debug(ctx, "_swrast_DestroyContext\n");
668   }
669
670   FREE( swrast->SpanArrays );
671   FREE( swrast->TexelBuffer );
672   FREE( swrast );
673
674   ctx->swrast_context = 0;
675}
676
677
678struct swrast_device_driver *
679_swrast_GetDeviceDriverReference( GLcontext *ctx )
680{
681   SWcontext *swrast = SWRAST_CONTEXT(ctx);
682   return &swrast->Driver;
683}
684
685void
686_swrast_flush( GLcontext *ctx )
687{
688   SWcontext *swrast = SWRAST_CONTEXT(ctx);
689   /* flush any pending fragments from rendering points */
690   if (swrast->PointSpan.end > 0) {
691      if (ctx->Visual.rgbMode) {
692         if (ctx->Texture._EnabledCoordUnits)
693            _swrast_write_texture_span(ctx, &(swrast->PointSpan));
694         else
695            _swrast_write_rgba_span(ctx, &(swrast->PointSpan));
696      }
697      else {
698         _swrast_write_index_span(ctx, &(swrast->PointSpan));
699      }
700      swrast->PointSpan.end = 0;
701   }
702}
703
704void
705_swrast_render_primitive( GLcontext *ctx, GLenum prim )
706{
707   SWcontext *swrast = SWRAST_CONTEXT(ctx);
708   if (swrast->Primitive == GL_POINTS && prim != GL_POINTS) {
709      _swrast_flush(ctx);
710   }
711   swrast->Primitive = prim;
712}
713
714
715void
716_swrast_render_start( GLcontext *ctx )
717{
718   SWcontext *swrast = SWRAST_CONTEXT(ctx);
719   if (swrast->Driver.SpanRenderStart)
720      swrast->Driver.SpanRenderStart( ctx );
721   swrast->PointSpan.end = 0;
722}
723
724void
725_swrast_render_finish( GLcontext *ctx )
726{
727   SWcontext *swrast = SWRAST_CONTEXT(ctx);
728   if (swrast->Driver.SpanRenderFinish)
729      swrast->Driver.SpanRenderFinish( ctx );
730
731   _swrast_flush(ctx);
732}
733
734
735#define SWRAST_DEBUG_VERTICES 0
736
737void
738_swrast_print_vertex( GLcontext *ctx, const SWvertex *v )
739{
740   GLuint i;
741
742   if (SWRAST_DEBUG_VERTICES) {
743      _mesa_debug(ctx, "win %f %f %f %f\n",
744                  v->win[0], v->win[1], v->win[2], v->win[3]);
745
746      for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
747	 if (ctx->Texture.Unit[i]._ReallyEnabled)
748	    _mesa_debug(ctx, "texcoord[%d] %f %f %f %f\n", i,
749                        v->texcoord[i][0], v->texcoord[i][1],
750                        v->texcoord[i][2], v->texcoord[i][3]);
751
752#if CHAN_TYPE == GL_FLOAT
753      _mesa_debug(ctx, "color %f %f %f %f\n",
754                  v->color[0], v->color[1], v->color[2], v->color[3]);
755      _mesa_debug(ctx, "spec %f %f %f %f\n",
756                  v->specular[0], v->specular[1],
757                  v->specular[2], v->specular[3]);
758#else
759      _mesa_debug(ctx, "color %d %d %d %d\n",
760                  v->color[0], v->color[1], v->color[2], v->color[3]);
761      _mesa_debug(ctx, "spec %d %d %d %d\n",
762                  v->specular[0], v->specular[1],
763                  v->specular[2], v->specular[3]);
764#endif
765      _mesa_debug(ctx, "fog %f\n", v->fog);
766      _mesa_debug(ctx, "index %d\n", v->index);
767      _mesa_debug(ctx, "pointsize %f\n", v->pointSize);
768      _mesa_debug(ctx, "\n");
769   }
770}
771
772
773/**
774 * Validate access to a PBO to be sure we're not going to read/write
775 * out of buffer bounds.
776 */
777GLvoid *
778_swrast_validate_pbo_access(const struct gl_pixelstore_attrib *pack,
779                            GLsizei width, GLsizei height, GLsizei depth,
780                            GLenum format, GLenum type, GLvoid *ptr)
781{
782   if (pack->BufferObj->Name == 0) {
783      /* no PBO */
784      return ptr;
785   }
786   else if (_mesa_validate_pbo_access(pack, width, height, depth, format,
787                                      type, ptr)) {
788      return ADD_POINTERS(pack->BufferObj->Data, ptr);
789   }
790   /* bad access! */
791   return NULL;
792}
793