1/**************************************************************************
2 *
3 * Copyright 2007 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/**
29 * Interface between 'draw' module's output and the llvmpipe rasterizer/setup
30 * code.  When the 'draw' module has finished filling a vertex buffer, the
31 * draw_arrays() functions below will be called.  Loop over the vertices and
32 * call the point/line/tri setup functions.
33 *
34 * Authors
35 *  Brian Paul
36 */
37
38
39#include "lp_setup_context.h"
40#include "draw/draw_vbuf.h"
41#include "draw/draw_vertex.h"
42#include "util/u_memory.h"
43
44
45#define LP_MAX_VBUF_INDEXES 1024
46#define LP_MAX_VBUF_SIZE    4096
47
48
49
50/** cast wrapper */
51static struct lp_setup_context *
52lp_setup_context(struct vbuf_render *vbr)
53{
54   return (struct lp_setup_context *) vbr;
55}
56
57
58
59static const struct vertex_info *
60lp_setup_get_vertex_info(struct vbuf_render *vbr)
61{
62   struct lp_setup_context *setup = lp_setup_context(vbr);
63
64   /* Vertex size/info depends on the latest state.
65    * The draw module may have issued additional state-change commands.
66    */
67   lp_setup_update_state(setup, FALSE);
68
69   return setup->vertex_info;
70}
71
72
73static boolean
74lp_setup_allocate_vertices(struct vbuf_render *vbr,
75                          ushort vertex_size, ushort nr_vertices)
76{
77   struct lp_setup_context *setup = lp_setup_context(vbr);
78   unsigned size = vertex_size * nr_vertices;
79
80   if (setup->vertex_buffer_size < size) {
81      align_free(setup->vertex_buffer);
82      setup->vertex_buffer = align_malloc(size, 16);
83      setup->vertex_buffer_size = size;
84   }
85
86   setup->vertex_size = vertex_size;
87   setup->nr_vertices = nr_vertices;
88
89   return setup->vertex_buffer != NULL;
90}
91
92static void
93lp_setup_release_vertices(struct vbuf_render *vbr)
94{
95   /* keep the old allocation for next time */
96}
97
98static void *
99lp_setup_map_vertices(struct vbuf_render *vbr)
100{
101   struct lp_setup_context *setup = lp_setup_context(vbr);
102   return setup->vertex_buffer;
103}
104
105static void
106lp_setup_unmap_vertices(struct vbuf_render *vbr,
107                       ushort min_index,
108                       ushort max_index )
109{
110   struct lp_setup_context *setup = lp_setup_context(vbr);
111   assert( setup->vertex_buffer_size >= (max_index+1) * setup->vertex_size );
112   /* do nothing */
113}
114
115
116static void
117lp_setup_set_primitive(struct vbuf_render *vbr, unsigned prim)
118{
119   lp_setup_context(vbr)->prim = prim;
120}
121
122typedef const float (*const_float4_ptr)[4];
123
124static INLINE const_float4_ptr get_vert( const void *vertex_buffer,
125                                         int index,
126                                         int stride )
127{
128   return (const_float4_ptr)((char *)vertex_buffer + index * stride);
129}
130
131/**
132 * draw elements / indexed primitives
133 */
134static void
135lp_setup_draw_elements(struct vbuf_render *vbr, const ushort *indices, uint nr)
136{
137   struct lp_setup_context *setup = lp_setup_context(vbr);
138   const unsigned stride = setup->vertex_info->size * sizeof(float);
139   const void *vertex_buffer = setup->vertex_buffer;
140   const boolean flatshade_first = setup->flatshade_first;
141   unsigned i;
142
143   assert(setup->setup.variant);
144
145   if (!lp_setup_update_state(setup, TRUE))
146      return;
147
148   switch (setup->prim) {
149   case PIPE_PRIM_POINTS:
150      for (i = 0; i < nr; i++) {
151         setup->point( setup,
152                       get_vert(vertex_buffer, indices[i-0], stride) );
153      }
154      break;
155
156   case PIPE_PRIM_LINES:
157      for (i = 1; i < nr; i += 2) {
158         setup->line( setup,
159                      get_vert(vertex_buffer, indices[i-1], stride),
160                      get_vert(vertex_buffer, indices[i-0], stride) );
161      }
162      break;
163
164   case PIPE_PRIM_LINE_STRIP:
165      for (i = 1; i < nr; i ++) {
166         setup->line( setup,
167                      get_vert(vertex_buffer, indices[i-1], stride),
168                      get_vert(vertex_buffer, indices[i-0], stride) );
169      }
170      break;
171
172   case PIPE_PRIM_LINE_LOOP:
173      for (i = 1; i < nr; i ++) {
174         setup->line( setup,
175                      get_vert(vertex_buffer, indices[i-1], stride),
176                      get_vert(vertex_buffer, indices[i-0], stride) );
177      }
178      if (nr) {
179         setup->line( setup,
180                      get_vert(vertex_buffer, indices[nr-1], stride),
181                      get_vert(vertex_buffer, indices[0], stride) );
182      }
183      break;
184
185   case PIPE_PRIM_TRIANGLES:
186      for (i = 2; i < nr; i += 3) {
187         setup->triangle( setup,
188                          get_vert(vertex_buffer, indices[i-2], stride),
189                          get_vert(vertex_buffer, indices[i-1], stride),
190                          get_vert(vertex_buffer, indices[i-0], stride) );
191      }
192      break;
193
194   case PIPE_PRIM_TRIANGLE_STRIP:
195      if (flatshade_first) {
196         for (i = 2; i < nr; i += 1) {
197            /* emit first triangle vertex as first triangle vertex */
198            setup->triangle( setup,
199                             get_vert(vertex_buffer, indices[i-2], stride),
200                             get_vert(vertex_buffer, indices[i+(i&1)-1], stride),
201                             get_vert(vertex_buffer, indices[i-(i&1)], stride) );
202
203         }
204      }
205      else {
206         for (i = 2; i < nr; i += 1) {
207            /* emit last triangle vertex as last triangle vertex */
208            setup->triangle( setup,
209                             get_vert(vertex_buffer, indices[i+(i&1)-2], stride),
210                             get_vert(vertex_buffer, indices[i-(i&1)-1], stride),
211                             get_vert(vertex_buffer, indices[i-0], stride) );
212         }
213      }
214      break;
215
216   case PIPE_PRIM_TRIANGLE_FAN:
217      if (flatshade_first) {
218         for (i = 2; i < nr; i += 1) {
219            /* emit first non-spoke vertex as first vertex */
220            setup->triangle( setup,
221                             get_vert(vertex_buffer, indices[i-1], stride),
222                             get_vert(vertex_buffer, indices[i-0], stride),
223                             get_vert(vertex_buffer, indices[0], stride) );
224         }
225      }
226      else {
227         for (i = 2; i < nr; i += 1) {
228            /* emit last non-spoke vertex as last vertex */
229            setup->triangle( setup,
230                             get_vert(vertex_buffer, indices[0], stride),
231                             get_vert(vertex_buffer, indices[i-1], stride),
232                             get_vert(vertex_buffer, indices[i-0], stride) );
233         }
234      }
235      break;
236
237   case PIPE_PRIM_QUADS:
238      /* GL quads don't follow provoking vertex convention */
239      if (flatshade_first) {
240         /* emit last quad vertex as first triangle vertex */
241         for (i = 3; i < nr; i += 4) {
242            setup->triangle( setup,
243                             get_vert(vertex_buffer, indices[i-0], stride),
244                             get_vert(vertex_buffer, indices[i-3], stride),
245                             get_vert(vertex_buffer, indices[i-2], stride) );
246
247            setup->triangle( setup,
248                             get_vert(vertex_buffer, indices[i-0], stride),
249                             get_vert(vertex_buffer, indices[i-2], stride),
250                             get_vert(vertex_buffer, indices[i-1], stride) );
251         }
252      }
253      else {
254         /* emit last quad vertex as last triangle vertex */
255         for (i = 3; i < nr; i += 4) {
256            setup->triangle( setup,
257                          get_vert(vertex_buffer, indices[i-3], stride),
258                          get_vert(vertex_buffer, indices[i-2], stride),
259                          get_vert(vertex_buffer, indices[i-0], stride) );
260
261            setup->triangle( setup,
262                             get_vert(vertex_buffer, indices[i-2], stride),
263                             get_vert(vertex_buffer, indices[i-1], stride),
264                             get_vert(vertex_buffer, indices[i-0], stride) );
265         }
266      }
267      break;
268
269   case PIPE_PRIM_QUAD_STRIP:
270      /* GL quad strips don't follow provoking vertex convention */
271      if (flatshade_first) {
272         /* emit last quad vertex as first triangle vertex */
273         for (i = 3; i < nr; i += 2) {
274            setup->triangle( setup,
275                             get_vert(vertex_buffer, indices[i-0], stride),
276                             get_vert(vertex_buffer, indices[i-3], stride),
277                             get_vert(vertex_buffer, indices[i-2], stride) );
278            setup->triangle( setup,
279                             get_vert(vertex_buffer, indices[i-0], stride),
280                             get_vert(vertex_buffer, indices[i-1], stride),
281                             get_vert(vertex_buffer, indices[i-3], stride) );
282         }
283      }
284      else {
285         /* emit last quad vertex as last triangle vertex */
286         for (i = 3; i < nr; i += 2) {
287            setup->triangle( setup,
288                             get_vert(vertex_buffer, indices[i-3], stride),
289                             get_vert(vertex_buffer, indices[i-2], stride),
290                             get_vert(vertex_buffer, indices[i-0], stride) );
291            setup->triangle( setup,
292                             get_vert(vertex_buffer, indices[i-1], stride),
293                             get_vert(vertex_buffer, indices[i-3], stride),
294                             get_vert(vertex_buffer, indices[i-0], stride) );
295         }
296      }
297      break;
298
299   case PIPE_PRIM_POLYGON:
300      /* Almost same as tri fan but the _first_ vertex specifies the flat
301       * shading color.
302       */
303      if (flatshade_first) {
304         /* emit first polygon  vertex as first triangle vertex */
305         for (i = 2; i < nr; i += 1) {
306            setup->triangle( setup,
307                             get_vert(vertex_buffer, indices[0], stride),
308                             get_vert(vertex_buffer, indices[i-1], stride),
309                             get_vert(vertex_buffer, indices[i-0], stride) );
310         }
311      }
312      else {
313         /* emit first polygon  vertex as last triangle vertex */
314         for (i = 2; i < nr; i += 1) {
315            setup->triangle( setup,
316                             get_vert(vertex_buffer, indices[i-1], stride),
317                             get_vert(vertex_buffer, indices[i-0], stride),
318                             get_vert(vertex_buffer, indices[0], stride) );
319         }
320      }
321      break;
322
323   default:
324      assert(0);
325   }
326}
327
328
329/**
330 * This function is hit when the draw module is working in pass-through mode.
331 * It's up to us to convert the vertex array into point/line/tri prims.
332 */
333static void
334lp_setup_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
335{
336   struct lp_setup_context *setup = lp_setup_context(vbr);
337   const unsigned stride = setup->vertex_info->size * sizeof(float);
338   const void *vertex_buffer =
339      (void *) get_vert(setup->vertex_buffer, start, stride);
340   const boolean flatshade_first = setup->flatshade_first;
341   unsigned i;
342
343   if (!lp_setup_update_state(setup, TRUE))
344      return;
345
346   switch (setup->prim) {
347   case PIPE_PRIM_POINTS:
348      for (i = 0; i < nr; i++) {
349         setup->point( setup,
350                       get_vert(vertex_buffer, i-0, stride) );
351      }
352      break;
353
354   case PIPE_PRIM_LINES:
355      for (i = 1; i < nr; i += 2) {
356         setup->line( setup,
357                      get_vert(vertex_buffer, i-1, stride),
358                      get_vert(vertex_buffer, i-0, stride) );
359      }
360      break;
361
362   case PIPE_PRIM_LINE_STRIP:
363      for (i = 1; i < nr; i ++) {
364         setup->line( setup,
365                      get_vert(vertex_buffer, i-1, stride),
366                      get_vert(vertex_buffer, i-0, stride) );
367      }
368      break;
369
370   case PIPE_PRIM_LINE_LOOP:
371      for (i = 1; i < nr; i ++) {
372         setup->line( setup,
373                      get_vert(vertex_buffer, i-1, stride),
374                      get_vert(vertex_buffer, i-0, stride) );
375      }
376      if (nr) {
377         setup->line( setup,
378                      get_vert(vertex_buffer, nr-1, stride),
379                      get_vert(vertex_buffer, 0, stride) );
380      }
381      break;
382
383   case PIPE_PRIM_TRIANGLES:
384      for (i = 2; i < nr; i += 3) {
385         setup->triangle( setup,
386                          get_vert(vertex_buffer, i-2, stride),
387                          get_vert(vertex_buffer, i-1, stride),
388                          get_vert(vertex_buffer, i-0, stride) );
389      }
390      break;
391
392   case PIPE_PRIM_TRIANGLE_STRIP:
393      if (flatshade_first) {
394         for (i = 2; i < nr; i++) {
395            /* emit first triangle vertex as first triangle vertex */
396            setup->triangle( setup,
397                             get_vert(vertex_buffer, i-2, stride),
398                             get_vert(vertex_buffer, i+(i&1)-1, stride),
399                             get_vert(vertex_buffer, i-(i&1), stride) );
400         }
401      }
402      else {
403         for (i = 2; i < nr; i++) {
404            /* emit last triangle vertex as last triangle vertex */
405            setup->triangle( setup,
406                             get_vert(vertex_buffer, i+(i&1)-2, stride),
407                             get_vert(vertex_buffer, i-(i&1)-1, stride),
408                             get_vert(vertex_buffer, i-0, stride) );
409         }
410      }
411      break;
412
413   case PIPE_PRIM_TRIANGLE_FAN:
414      if (flatshade_first) {
415         for (i = 2; i < nr; i += 1) {
416            /* emit first non-spoke vertex as first vertex */
417            setup->triangle( setup,
418                             get_vert(vertex_buffer, i-1, stride),
419                             get_vert(vertex_buffer, i-0, stride),
420                             get_vert(vertex_buffer, 0, stride)  );
421         }
422      }
423      else {
424         for (i = 2; i < nr; i += 1) {
425            /* emit last non-spoke vertex as last vertex */
426            setup->triangle( setup,
427                             get_vert(vertex_buffer, 0, stride),
428                             get_vert(vertex_buffer, i-1, stride),
429                             get_vert(vertex_buffer, i-0, stride) );
430         }
431      }
432      break;
433
434   case PIPE_PRIM_QUADS:
435      /* GL quads don't follow provoking vertex convention */
436      if (flatshade_first) {
437         /* emit last quad vertex as first triangle vertex */
438         for (i = 3; i < nr; i += 4) {
439            setup->triangle( setup,
440                             get_vert(vertex_buffer, i-0, stride),
441                             get_vert(vertex_buffer, i-3, stride),
442                             get_vert(vertex_buffer, i-2, stride) );
443            setup->triangle( setup,
444                             get_vert(vertex_buffer, i-0, stride),
445                             get_vert(vertex_buffer, i-2, stride),
446                             get_vert(vertex_buffer, i-1, stride) );
447         }
448      }
449      else {
450         /* emit last quad vertex as last triangle vertex */
451         for (i = 3; i < nr; i += 4) {
452            setup->triangle( setup,
453                             get_vert(vertex_buffer, i-3, stride),
454                             get_vert(vertex_buffer, i-2, stride),
455                             get_vert(vertex_buffer, i-0, stride) );
456            setup->triangle( setup,
457                             get_vert(vertex_buffer, i-2, stride),
458                             get_vert(vertex_buffer, i-1, stride),
459                             get_vert(vertex_buffer, i-0, stride) );
460         }
461      }
462      break;
463
464   case PIPE_PRIM_QUAD_STRIP:
465      /* GL quad strips don't follow provoking vertex convention */
466      if (flatshade_first) {
467         /* emit last quad vertex as first triangle vertex */
468         for (i = 3; i < nr; i += 2) {
469            setup->triangle( setup,
470                             get_vert(vertex_buffer, i-0, stride),
471                             get_vert(vertex_buffer, i-3, stride),
472                             get_vert(vertex_buffer, i-2, stride) );
473            setup->triangle( setup,
474                             get_vert(vertex_buffer, i-0, stride),
475                             get_vert(vertex_buffer, i-1, stride),
476                             get_vert(vertex_buffer, i-3, stride) );
477         }
478      }
479      else {
480         /* emit last quad vertex as last triangle vertex */
481         for (i = 3; i < nr; i += 2) {
482            setup->triangle( setup,
483                             get_vert(vertex_buffer, i-3, stride),
484                             get_vert(vertex_buffer, i-2, stride),
485                             get_vert(vertex_buffer, i-0, stride) );
486            setup->triangle( setup,
487                             get_vert(vertex_buffer, i-1, stride),
488                             get_vert(vertex_buffer, i-3, stride),
489                             get_vert(vertex_buffer, i-0, stride) );
490         }
491      }
492      break;
493
494   case PIPE_PRIM_POLYGON:
495      /* Almost same as tri fan but the _first_ vertex specifies the flat
496       * shading color.
497       */
498      if (flatshade_first) {
499         /* emit first polygon  vertex as first triangle vertex */
500         for (i = 2; i < nr; i += 1) {
501            setup->triangle( setup,
502                             get_vert(vertex_buffer, 0, stride),
503                             get_vert(vertex_buffer, i-1, stride),
504                             get_vert(vertex_buffer, i-0, stride) );
505         }
506      }
507      else {
508         /* emit first polygon  vertex as last triangle vertex */
509         for (i = 2; i < nr; i += 1) {
510            setup->triangle( setup,
511                             get_vert(vertex_buffer, i-1, stride),
512                             get_vert(vertex_buffer, i-0, stride),
513                             get_vert(vertex_buffer, 0, stride) );
514         }
515      }
516      break;
517
518   default:
519      assert(0);
520   }
521}
522
523
524
525static void
526lp_setup_vbuf_destroy(struct vbuf_render *vbr)
527{
528   struct lp_setup_context *setup = lp_setup_context(vbr);
529   if (setup->vertex_buffer) {
530      align_free(setup->vertex_buffer);
531      setup->vertex_buffer = NULL;
532   }
533   lp_setup_destroy(setup);
534}
535
536
537/**
538 * Create the post-transform vertex handler for the given context.
539 */
540void
541lp_setup_init_vbuf(struct lp_setup_context *setup)
542{
543   setup->base.max_indices = LP_MAX_VBUF_INDEXES;
544   setup->base.max_vertex_buffer_bytes = LP_MAX_VBUF_SIZE;
545
546   setup->base.get_vertex_info = lp_setup_get_vertex_info;
547   setup->base.allocate_vertices = lp_setup_allocate_vertices;
548   setup->base.map_vertices = lp_setup_map_vertices;
549   setup->base.unmap_vertices = lp_setup_unmap_vertices;
550   setup->base.set_primitive = lp_setup_set_primitive;
551   setup->base.draw_elements = lp_setup_draw_elements;
552   setup->base.draw_arrays = lp_setup_draw_arrays;
553   setup->base.release_vertices = lp_setup_release_vertices;
554   setup->base.destroy = lp_setup_vbuf_destroy;
555}
556