geometry shaders: make gs work with changable primitives and variable number of vertices
[mesa.git] / src / gallium / auxiliary / draw / draw_pt_varray.c
1 /**************************************************************************
2 *
3 * Copyright 2008 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 "util/u_math.h"
29 #include "util/u_memory.h"
30
31 #include "draw/draw_context.h"
32 #include "draw/draw_private.h"
33 #include "draw/draw_pt.h"
34
35 #define FETCH_MAX 256
36 #define DRAW_MAX (FETCH_MAX+8)
37
38 struct varray_frontend {
39 struct draw_pt_front_end base;
40 struct draw_context *draw;
41
42 ushort draw_elts[DRAW_MAX];
43 unsigned fetch_elts[FETCH_MAX];
44
45 unsigned driver_fetch_max;
46 unsigned fetch_max;
47
48 struct draw_pt_middle_end *middle;
49
50 unsigned input_prim;
51 unsigned output_prim;
52 };
53
54
55 static void varray_flush_linear(struct varray_frontend *varray,
56 unsigned start, unsigned count)
57 {
58 if (count) {
59 assert(varray->middle->run_linear);
60 varray->middle->run_linear(varray->middle, start, count);
61 }
62 }
63
64 static void varray_line_loop_segment(struct varray_frontend *varray,
65 unsigned start,
66 unsigned segment_start,
67 unsigned segment_count,
68 boolean end )
69 {
70 assert(segment_count < varray->fetch_max);
71 if (segment_count >= 1) {
72 unsigned nr = 0, i;
73
74 for (i = 0; i < segment_count; i++)
75 varray->fetch_elts[nr++] = start + segment_start + i;
76
77 if (end)
78 varray->fetch_elts[nr++] = start;
79
80 assert(nr <= FETCH_MAX);
81
82 varray->middle->run(varray->middle,
83 varray->fetch_elts,
84 nr,
85 varray->draw_elts, /* ie. linear */
86 nr);
87 }
88 }
89
90
91
92 static void varray_fan_segment(struct varray_frontend *varray,
93 unsigned start,
94 unsigned segment_start,
95 unsigned segment_count )
96 {
97 assert(segment_count < varray->fetch_max);
98 if (segment_count >= 2) {
99 unsigned nr = 0, i;
100
101 if (segment_start != 0)
102 varray->fetch_elts[nr++] = start;
103
104 for (i = 0 ; i < segment_count; i++)
105 varray->fetch_elts[nr++] = start + segment_start + i;
106
107 assert(nr <= FETCH_MAX);
108
109 varray->middle->run(varray->middle,
110 varray->fetch_elts,
111 nr,
112 varray->draw_elts, /* ie. linear */
113 nr);
114 }
115 }
116
117
118
119
120 #define FUNC varray_run
121 #include "draw_pt_varray_tmp_linear.h"
122
123 static unsigned decompose_prim[PIPE_PRIM_POLYGON + 1] = {
124 PIPE_PRIM_POINTS,
125 PIPE_PRIM_LINES,
126 PIPE_PRIM_LINE_STRIP, /* decomposed LINELOOP */
127 PIPE_PRIM_LINE_STRIP,
128 PIPE_PRIM_TRIANGLES,
129 PIPE_PRIM_TRIANGLE_STRIP,
130 PIPE_PRIM_TRIANGLE_FAN,
131 PIPE_PRIM_QUADS,
132 PIPE_PRIM_QUAD_STRIP,
133 PIPE_PRIM_POLYGON
134 };
135
136
137
138 static void varray_prepare(struct draw_pt_front_end *frontend,
139 unsigned in_prim,
140 unsigned out_prim,
141 struct draw_pt_middle_end *middle,
142 unsigned opt)
143 {
144 struct varray_frontend *varray = (struct varray_frontend *)frontend;
145
146 varray->base.run = varray_run;
147
148 varray->input_prim = in_prim;
149 varray->output_prim = decompose_prim[out_prim];
150
151 varray->middle = middle;
152 middle->prepare(middle, varray->input_prim,
153 varray->output_prim, opt, &varray->driver_fetch_max );
154
155 /* check that the max is even */
156 assert((varray->driver_fetch_max & 1) == 0);
157
158 varray->fetch_max = MIN2(FETCH_MAX, varray->driver_fetch_max);
159 }
160
161
162
163
164 static void varray_finish(struct draw_pt_front_end *frontend)
165 {
166 struct varray_frontend *varray = (struct varray_frontend *)frontend;
167 varray->middle->finish(varray->middle);
168 varray->middle = NULL;
169 }
170
171 static void varray_destroy(struct draw_pt_front_end *frontend)
172 {
173 FREE(frontend);
174 }
175
176
177 struct draw_pt_front_end *draw_pt_varray(struct draw_context *draw)
178 {
179 ushort i;
180 struct varray_frontend *varray = CALLOC_STRUCT(varray_frontend);
181 if (varray == NULL)
182 return NULL;
183
184 varray->base.prepare = varray_prepare;
185 varray->base.run = NULL;
186 varray->base.finish = varray_finish;
187 varray->base.destroy = varray_destroy;
188 varray->draw = draw;
189
190 for (i = 0; i < DRAW_MAX; i++) {
191 varray->draw_elts[i] = i;
192 }
193
194 return &varray->base;
195 }