brw_draw.c revision 14ec34d64733478b773190cb62be37b7b2871a7f
1/**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * 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
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28#include <stdlib.h>
29
30#include "glheader.h"
31#include "context.h"
32#include "state.h"
33#include "api_validate.h"
34#include "enums.h"
35
36#include "brw_draw.h"
37#include "brw_defines.h"
38#include "brw_attrib.h"
39#include "brw_context.h"
40#include "brw_aub.h"
41#include "brw_state.h"
42#include "brw_fallback.h"
43
44#include "intel_ioctl.h"
45#include "intel_batchbuffer.h"
46#include "intel_buffer_objects.h"
47
48
49
50
51
52
53static GLuint hw_prim[GL_POLYGON+1] = {
54   _3DPRIM_POINTLIST,
55   _3DPRIM_LINELIST,
56   _3DPRIM_LINELOOP,
57   _3DPRIM_LINESTRIP,
58   _3DPRIM_TRILIST,
59   _3DPRIM_TRISTRIP,
60   _3DPRIM_TRIFAN,
61   _3DPRIM_QUADLIST,
62   _3DPRIM_QUADSTRIP,
63   _3DPRIM_POLYGON
64};
65
66
67static const GLenum reduced_prim[GL_POLYGON+1] = {
68   GL_POINTS,
69   GL_LINES,
70   GL_LINES,
71   GL_LINES,
72   GL_TRIANGLES,
73   GL_TRIANGLES,
74   GL_TRIANGLES,
75   GL_TRIANGLES,
76   GL_TRIANGLES,
77   GL_TRIANGLES
78};
79
80
81/* When the primitive changes, set a state bit and re-validate.  Not
82 * the nicest and would rather deal with this by having all the
83 * programs be immune to the active primitive (ie. cope with all
84 * possibilities).  That may not be realistic however.
85 */
86static GLuint brw_set_prim(struct brw_context *brw, GLenum prim)
87{
88   if (INTEL_DEBUG & DEBUG_PRIMS)
89      _mesa_printf("PRIM: %s\n", _mesa_lookup_enum_by_nr(prim));
90
91   /* Slight optimization to avoid the GS program when not needed:
92    */
93   if (prim == GL_QUAD_STRIP &&
94       brw->attribs.Light->ShadeModel != GL_FLAT &&
95       brw->attribs.Polygon->FrontMode == GL_FILL &&
96       brw->attribs.Polygon->BackMode == GL_FILL)
97      prim = GL_TRIANGLE_STRIP;
98
99   if (prim != brw->primitive) {
100      brw->primitive = prim;
101      brw->state.dirty.brw |= BRW_NEW_PRIMITIVE;
102
103      if (reduced_prim[prim] != brw->intel.reduced_primitive) {
104	 brw->intel.reduced_primitive = reduced_prim[prim];
105	 brw->state.dirty.brw |= BRW_NEW_REDUCED_PRIMITIVE;
106      }
107
108      brw_validate_state(brw);
109   }
110
111   return hw_prim[prim];
112}
113
114
115static GLuint trim(GLenum prim, GLuint length)
116{
117   if (prim == GL_QUAD_STRIP)
118      return length > 3 ? (length - length % 2) : 0;
119   else if (prim == GL_QUADS)
120      return length - length % 4;
121   else
122      return length;
123}
124
125
126
127
128static void brw_emit_prim( struct brw_context *brw,
129			   const struct brw_draw_prim *prim )
130
131{
132   struct brw_3d_primitive prim_packet;
133
134   if (INTEL_DEBUG & DEBUG_PRIMS)
135      _mesa_printf("PRIM: %s %d %d\n", _mesa_lookup_enum_by_nr(prim->mode),
136		   prim->start, prim->count);
137
138   prim_packet.header.opcode = CMD_3D_PRIM;
139   prim_packet.header.length = sizeof(prim_packet)/4 - 2;
140   prim_packet.header.pad = 0;
141   prim_packet.header.topology = brw_set_prim(brw, prim->mode);
142   prim_packet.header.indexed = prim->indexed;
143
144   prim_packet.verts_per_instance = trim(prim->mode, prim->count);
145   prim_packet.start_vert_location = prim->start;
146   prim_packet.instance_count = 1;
147   prim_packet.start_instance_location = 0;
148   prim_packet.base_vert_location = 0;
149
150   if (prim_packet.verts_per_instance) {
151      intel_batchbuffer_data( brw->intel.batch, &prim_packet, sizeof(prim_packet),
152			      INTEL_BATCH_CLIPRECTS);
153   }
154}
155
156
157
158static void update_current_size( struct gl_client_array *array)
159{
160   const GLfloat *ptr = (const GLfloat *)array->Ptr;
161
162   assert(array->StrideB == 0);
163   assert(array->Type == GL_FLOAT || array->Type == GL_UNSIGNED_BYTE);
164
165   if (ptr[3] != 1.0)
166      array->Size = 4;
167   else if (ptr[2] != 0.0)
168      array->Size = 3;
169   else if (ptr[1] != 0.0)
170      array->Size = 2;
171   else
172      array->Size = 1;
173}
174
175
176
177/* Fill in any gaps in passed arrays with pointers to current
178 * attributes:
179 */
180static void brw_merge_inputs( struct brw_context *brw,
181		       const struct gl_client_array *arrays[])
182{
183   struct gl_client_array *current_values = brw->vb.current_values;
184   struct brw_vertex_element *inputs = brw->vb.inputs;
185   struct brw_vertex_info old = brw->vb.info;
186   GLuint i;
187
188   memset(inputs, 0, sizeof(*inputs));
189   memset(&brw->vb.info, 0, sizeof(brw->vb.info));
190
191   for (i = 0; i < BRW_ATTRIB_MAX; i++) {
192      if (arrays[i] && arrays[i]->Enabled)
193      {
194	 brw->vb.inputs[i].glarray = arrays[i];
195	 brw->vb.info.varying |= 1 << i;
196      }
197      else
198      {
199	 brw->vb.inputs[i].glarray = &current_values[i];
200	 update_current_size(&current_values[i]);
201      }
202
203      brw->vb.info.sizes[i/16] |= (inputs[i].glarray->Size - 1) << ((i%16) * 2);
204   }
205
206   /* Raise statechanges if input sizes and varying have changed:
207    */
208   if (memcmp(brw->vb.info.sizes, old.sizes, sizeof(old.sizes)) != 0)
209      brw->state.dirty.brw |= BRW_NEW_INPUT_DIMENSIONS;
210
211   if (brw->vb.info.varying != old.varying)
212      brw->state.dirty.brw |= BRW_NEW_INPUT_VARYING;
213}
214
215static GLboolean check_fallbacks( struct brw_context *brw,
216				  const struct brw_draw_prim *prim,
217				  GLuint nr_prims )
218{
219   GLuint i;
220
221   if (!brw->intel.strict_conformance)
222      return GL_FALSE;
223
224   if (brw->attribs.Polygon->SmoothFlag) {
225      for (i = 0; i < nr_prims; i++)
226	 if (reduced_prim[prim[i].mode] == GL_TRIANGLES)
227	    return GL_TRUE;
228   }
229
230   /* BRW hardware will do AA lines, but they are non-conformant it
231    * seems.  TBD whether we keep this fallback:
232    */
233   if (brw->attribs.Line->SmoothFlag) {
234      for (i = 0; i < nr_prims; i++)
235	 if (reduced_prim[prim[i].mode] == GL_LINES)
236	    return GL_TRUE;
237   }
238
239   /* Stipple -- these fallbacks could be resolved with a little
240    * bit of work?
241    */
242   if (brw->attribs.Line->StippleFlag) {
243      for (i = 0; i < nr_prims; i++) {
244	 /* GS doesn't get enough information to know when to reset
245	  * the stipple counter?!?
246	  */
247	 if (prim[i].mode == GL_LINE_LOOP)
248	    return GL_TRUE;
249
250	 if (prim[i].mode == GL_POLYGON &&
251	     (brw->attribs.Polygon->FrontMode == GL_LINE ||
252	      brw->attribs.Polygon->BackMode == GL_LINE))
253	    return GL_TRUE;
254      }
255   }
256
257
258   if (brw->attribs.Point->SmoothFlag) {
259      for (i = 0; i < nr_prims; i++)
260	 if (prim[i].mode == GL_POINTS)
261	    return GL_TRUE;
262   }
263
264   return GL_FALSE;
265}
266
267
268GLboolean brw_draw_prims( GLcontext *ctx,
269			  const struct gl_client_array *arrays[],
270			  const struct brw_draw_prim *prim,
271			  GLuint nr_prims,
272			  const struct brw_draw_index_buffer *ib,
273			  GLuint min_index,
274			  GLuint max_index,
275			  GLuint flags )
276{
277   struct intel_context *intel = intel_context(ctx);
278   struct brw_context *brw = brw_context(ctx);
279   GLboolean retval = GL_FALSE;
280   GLuint i;
281
282   if (ctx->NewState)
283      _mesa_update_state( ctx );
284
285   /* Bind all inputs, derive varying and size information:
286    */
287   brw_merge_inputs( brw, arrays );
288
289   /* Have to validate state quite late.  Will rebuild tnl_program,
290    * which depends on varying information.
291    *
292    * Note this is where brw->vs->prog_data.inputs_read is calculated,
293    * so can't access it earlier.
294    */
295
296   LOCK_HARDWARE(intel);
297   {
298      assert(intel->locked);
299
300      /* Set the first primitive early, ahead of validate_state:
301       */
302      brw_set_prim(brw, prim[0].mode);
303
304      /* XXX:  Need to separate validate and upload of state.
305       */
306      brw_validate_state( brw );
307
308      /* Various fallback checks:
309       */
310      if (brw->intel.Fallback)
311	 goto out;
312
313      if (check_fallbacks( brw, prim, nr_prims ))
314	 goto out;
315
316      /* Upload index, vertex data:
317       */
318      if (ib)
319	 brw_upload_indices( brw, ib );
320
321      if (!brw_upload_vertices( brw, min_index, max_index)) {
322	 goto out;
323      }
324
325      /* Emit prims to batchbuffer:
326       */
327      for (i = 0; i < nr_prims; i++) {
328	 brw_emit_prim(brw, &prim[i]);
329      }
330
331      retval = GL_TRUE;
332   }
333
334 out:
335
336   /* Currently have to do this to synchronize with the map/unmap of
337    * the vertex buffer in brw_exec_api.c.  Not sure if there is any
338    * way around this, as not every flush is due to a buffer filling
339    * up.
340    */
341   intel_batchbuffer_flush( brw->intel.batch );
342
343   if (intel->thrashing) {
344      bmSetFence(intel);
345   }
346
347   /* Free any old data so it doesn't clog up texture memory - we
348    * won't be referencing it again.
349    */
350   while (brw->vb.upload.wrap != brw->vb.upload.buf) {
351      ctx->Driver.BufferData(ctx,
352			     GL_ARRAY_BUFFER_ARB,
353			     BRW_UPLOAD_INIT_SIZE,
354			     NULL,
355			     GL_DYNAMIC_DRAW_ARB,
356			     brw->vb.upload.vbo[brw->vb.upload.wrap]);
357      brw->vb.upload.wrap++;
358      brw->vb.upload.wrap %= BRW_NR_UPLOAD_BUFS;
359   }
360
361   UNLOCK_HARDWARE(intel);
362   return retval;
363}
364
365static void brw_invalidate_vbo_cb( struct intel_context *intel, void *ptr )
366{
367   /* nothing to do, we don't rely on the contents being preserved */
368}
369
370
371void brw_draw_init( struct brw_context *brw )
372{
373   GLcontext *ctx = &brw->intel.ctx;
374   GLuint i;
375
376   brw->vb.upload.size = BRW_UPLOAD_INIT_SIZE;
377
378   for (i = 0; i < BRW_NR_UPLOAD_BUFS; i++) {
379      brw->vb.upload.vbo[i] = ctx->Driver.NewBufferObject(ctx, 1, GL_ARRAY_BUFFER_ARB);
380
381      /* XXX: Set these to no-backing-store
382       */
383      bmBufferSetInvalidateCB(&brw->intel,
384			      intel_bufferobj_buffer(intel_buffer_object(brw->vb.upload.vbo[i])),
385			      brw_invalidate_vbo_cb,
386			      &brw->intel,
387			      GL_TRUE);
388
389   }
390
391   ctx->Driver.BufferData( ctx,
392			   GL_ARRAY_BUFFER_ARB,
393			   BRW_UPLOAD_INIT_SIZE,
394			   NULL,
395			   GL_DYNAMIC_DRAW_ARB,
396			   brw->vb.upload.vbo[0] );
397
398
399   brw_init_current_values(ctx, brw->vb.current_values);
400}
401
402void brw_draw_destroy( struct brw_context *brw )
403{
404   GLcontext *ctx = &brw->intel.ctx;
405   GLuint i;
406
407   for (i = 0; i < BRW_NR_UPLOAD_BUFS; i++)
408      ctx->Driver.DeleteBuffer(ctx, brw->vb.upload.vbo[i]);
409}
410