1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Keith Whitwell <keithw@vmware.com>
26 */
27
28#include "main/glheader.h"
29
30#include "main/macros.h"
31#include "main/state.h"
32#include "tnl/tnl.h"
33#include "tnl/t_context.h"
34#include "tnl/t_pipeline.h"
35#include "tnl/t_vertex.h"
36#include "swrast_setup.h"
37#include "ss_context.h"
38#include "ss_triangle.h"
39
40
41/* Need to check lighting state and vertex program state to know
42 * if two-sided lighting is in effect.
43 */
44#define _SWSETUP_NEW_RENDERINDEX (_NEW_POLYGON|_NEW_LIGHT|_NEW_PROGRAM)
45
46
47#define VARYING_EMIT_STYLE  EMIT_4F
48
49
50GLboolean
51_swsetup_CreateContext( struct gl_context *ctx )
52{
53   SScontext *swsetup = calloc(1, sizeof(SScontext));
54
55   if (!swsetup)
56      return GL_FALSE;
57
58   ctx->swsetup_context = swsetup;
59
60   swsetup->NewState = ~0;
61   _swsetup_trifuncs_init( ctx );
62
63   _tnl_init_vertices( ctx, ctx->Const.MaxArrayLockSize + 12,
64		       sizeof(SWvertex) );
65
66
67   return GL_TRUE;
68}
69
70void
71_swsetup_DestroyContext( struct gl_context *ctx )
72{
73   SScontext *swsetup = SWSETUP_CONTEXT(ctx);
74
75   if (swsetup) {
76      free(swsetup);
77      ctx->swsetup_context = 0;
78   }
79
80   _tnl_free_vertices( ctx );
81}
82
83static void
84_swsetup_RenderPrimitive( struct gl_context *ctx, GLenum mode )
85{
86   SWSETUP_CONTEXT(ctx)->render_prim = mode;
87   _swrast_render_primitive( ctx, mode );
88}
89
90
91/**
92 * Helper macros for setup_vertex_format()
93 */
94#define SWZ ((SWvertex *)0)
95#define SWOffset(MEMBER) (((char *)&(SWZ->MEMBER)) - ((char *)SWZ))
96
97#define EMIT_ATTR( ATTR, STYLE, MEMBER )	\
98do {						\
99   map[e].attrib = (ATTR);			\
100   map[e].format = (STYLE);			\
101   map[e].offset = SWOffset(MEMBER);	       	\
102   e++;						\
103} while (0)
104
105
106/**
107 * Tell the tnl module how to build SWvertex objects for swrast.
108 * We'll build the map[] array with that info and pass it to
109 * _tnl_install_attrs().
110 */
111static void
112setup_vertex_format(struct gl_context *ctx)
113{
114   TNLcontext *tnl = TNL_CONTEXT(ctx);
115   SScontext *swsetup = SWSETUP_CONTEXT(ctx);
116   GLboolean intColors = !ctx->FragmentProgram._Current
117                      && !_mesa_ati_fragment_shader_enabled(ctx)
118                      && ctx->RenderMode == GL_RENDER
119                      && CHAN_TYPE != GL_FLOAT;
120
121   if (intColors != swsetup->intColors ||
122       tnl->render_inputs_bitset != swsetup->last_index_bitset) {
123      GLbitfield64 index_bitset = tnl->render_inputs_bitset;
124      struct tnl_attr_map map[_TNL_ATTRIB_MAX];
125      unsigned int i, e = 0;
126
127      swsetup->intColors = intColors;
128
129      EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_4F_VIEWPORT, attrib[VARYING_SLOT_POS] );
130
131      if (index_bitset & BITFIELD64_BIT(_TNL_ATTRIB_COLOR0)) {
132         if (swsetup->intColors)
133            EMIT_ATTR( _TNL_ATTRIB_COLOR0, EMIT_4CHAN_4F_RGBA, color );
134         else
135            EMIT_ATTR( _TNL_ATTRIB_COLOR0, EMIT_4F, attrib[VARYING_SLOT_COL0]);
136      }
137
138      if (index_bitset & BITFIELD64_BIT(_TNL_ATTRIB_COLOR1)) {
139         EMIT_ATTR( _TNL_ATTRIB_COLOR1, EMIT_4F, attrib[VARYING_SLOT_COL1]);
140      }
141
142      if (index_bitset & BITFIELD64_BIT(_TNL_ATTRIB_FOG)) {
143         const GLint emit = ctx->FragmentProgram._Current ? EMIT_4F : EMIT_1F;
144         EMIT_ATTR( _TNL_ATTRIB_FOG, emit, attrib[VARYING_SLOT_FOGC]);
145      }
146
147      if (index_bitset & BITFIELD64_RANGE(_TNL_ATTRIB_TEX0, _TNL_NUM_TEX))
148      {
149         for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
150            if (index_bitset & BITFIELD64_BIT(_TNL_ATTRIB_TEX(i))) {
151               EMIT_ATTR( _TNL_ATTRIB_TEX(i), EMIT_4F,
152                          attrib[VARYING_SLOT_TEX0 + i] );
153            }
154         }
155      }
156
157      /* shader varying vars */
158      if (index_bitset & BITFIELD64_RANGE(_TNL_ATTRIB_GENERIC0, _TNL_NUM_GENERIC)) {
159         for (i = 0; i < ctx->Const.MaxVarying; i++) {
160            if (index_bitset & BITFIELD64_BIT(_TNL_ATTRIB_GENERIC(i))) {
161               EMIT_ATTR( _TNL_ATTRIB_GENERIC(i), VARYING_EMIT_STYLE,
162                          attrib[VARYING_SLOT_VAR0 + i] );
163            }
164         }
165      }
166
167      if (index_bitset & BITFIELD64_BIT(_TNL_ATTRIB_POINTSIZE))
168         EMIT_ATTR( _TNL_ATTRIB_POINTSIZE, EMIT_1F, pointSize );
169
170      _tnl_install_attrs( ctx, map, e,
171                          tnl->_WindowMap.m,
172                          sizeof(SWvertex) );
173
174      swsetup->last_index_bitset = index_bitset;
175   }
176}
177
178
179/**
180 * Prepare to render a vertex buffer.
181 * Called via tnl->Driver.Render.Start.
182 */
183static void
184_swsetup_RenderStart( struct gl_context *ctx )
185{
186   SScontext *swsetup = SWSETUP_CONTEXT(ctx);
187   TNLcontext *tnl = TNL_CONTEXT(ctx);
188   struct vertex_buffer *VB = &tnl->vb;
189
190   if (swsetup->NewState & _SWSETUP_NEW_RENDERINDEX) {
191      _swsetup_choose_trifuncs(ctx);
192   }
193
194   if (swsetup->NewState & _NEW_PROGRAM) {
195      swsetup->last_index_bitset = 0;
196   }
197
198   swsetup->NewState = 0;
199
200   /* This will change if drawing unfilled tris */
201   _swrast_SetFacing(ctx, 0);
202
203   _swrast_render_start(ctx);
204
205   /* Important */
206   VB->AttribPtr[VERT_ATTRIB_POS] = VB->NdcPtr;
207
208   setup_vertex_format(ctx);
209}
210
211
212/*
213 * We patch this function into tnl->Driver.Render.Finish.
214 * It's called when we finish rendering a vertex buffer.
215 */
216static void
217_swsetup_RenderFinish( struct gl_context *ctx )
218{
219   _swrast_render_finish( ctx );
220}
221
222void
223_swsetup_InvalidateState( struct gl_context *ctx, GLuint new_state )
224{
225   SScontext *swsetup = SWSETUP_CONTEXT(ctx);
226   swsetup->NewState |= new_state;
227   _tnl_invalidate_vertex_state( ctx, new_state );
228}
229
230
231void
232_swsetup_Wakeup( struct gl_context *ctx )
233{
234   TNLcontext *tnl = TNL_CONTEXT(ctx);
235   SScontext *swsetup = SWSETUP_CONTEXT(ctx);
236
237   tnl->Driver.Render.Start = _swsetup_RenderStart;
238   tnl->Driver.Render.Finish = _swsetup_RenderFinish;
239   tnl->Driver.Render.PrimitiveNotify = _swsetup_RenderPrimitive;
240   tnl->Driver.Render.Interp = _tnl_interp;
241   tnl->Driver.Render.CopyPV = _tnl_copy_pv;
242   tnl->Driver.Render.ClippedPolygon = _tnl_RenderClippedPolygon; /* new */
243   tnl->Driver.Render.ClippedLine = _tnl_RenderClippedLine; /* new */
244   /* points */
245   /* line */
246   /* triangle */
247   /* quad */
248   tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts;
249   tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts;
250   tnl->Driver.Render.ResetLineStipple = _swrast_ResetLineStipple;
251   tnl->Driver.Render.BuildVertices = _tnl_build_vertices;
252   tnl->Driver.Render.Multipass = 0;
253
254   _tnl_invalidate_vertices( ctx, ~0 );
255   _tnl_need_projected_coords( ctx, GL_TRUE );
256   _swsetup_InvalidateState( ctx, ~0 );
257
258   swsetup->verts = (SWvertex *)tnl->clipspace.vertex_buf;
259   swsetup->last_index_bitset = 0;
260}
261
262
263/**
264 * Populate a swrast SWvertex from an attrib-style vertex.
265 */
266void
267_swsetup_Translate( struct gl_context *ctx, const void *vertex, SWvertex *dest )
268{
269   TNLcontext *tnl = TNL_CONTEXT(ctx);
270   const GLfloat *m = tnl->_WindowMap.m;
271   GLfloat tmp[4];
272   GLuint i;
273
274   _tnl_get_attr( ctx, vertex, _TNL_ATTRIB_POS, tmp );
275
276   dest->attrib[VARYING_SLOT_POS][0] = m[0]  * tmp[0] + m[12];
277   dest->attrib[VARYING_SLOT_POS][1] = m[5]  * tmp[1] + m[13];
278   dest->attrib[VARYING_SLOT_POS][2] = m[10] * tmp[2] + m[14];
279   dest->attrib[VARYING_SLOT_POS][3] =         tmp[3];
280
281   /** XXX try to limit these loops someday */
282   for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++)
283      _tnl_get_attr( ctx, vertex, _TNL_ATTRIB_TEX0 + i,
284                     dest->attrib[VARYING_SLOT_TEX0 + i] );
285
286   for (i = 0 ; i < ctx->Const.MaxVarying ; i++)
287      _tnl_get_attr( ctx, vertex, _TNL_ATTRIB_GENERIC0 + i,
288                     dest->attrib[VARYING_SLOT_VAR0 + i] );
289
290   _tnl_get_attr( ctx, vertex, _TNL_ATTRIB_COLOR0,
291                  dest->attrib[VARYING_SLOT_COL0] );
292
293   UNCLAMPED_FLOAT_TO_RGBA_CHAN(dest->color, dest->attrib[VARYING_SLOT_COL0]);
294
295   _tnl_get_attr( ctx, vertex, _TNL_ATTRIB_COLOR1,
296                  dest->attrib[VARYING_SLOT_COL1]);
297
298   _tnl_get_attr( ctx, vertex, _TNL_ATTRIB_FOG, tmp );
299   dest->attrib[VARYING_SLOT_FOGC][0] = tmp[0];
300
301   /* XXX See _tnl_get_attr about pointsize ... */
302   _tnl_get_attr( ctx, vertex, _TNL_ATTRIB_POINTSIZE, tmp );
303   dest->pointSize = tmp[0];
304}
305
306