578ddf62dcb26fb300e70f6e67ae5021d04943f4
[mesa.git] / src / gallium / drivers / cell / ppu / cell_vbuf.c
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 * Vertex buffer code. The draw module transforms vertices to window
30 * coords, etc. and emits the vertices into buffer supplied by this module.
31 * When a vertex buffer is full, or we flush, we'll send the vertex data
32 * to the SPUs.
33 *
34 * Authors
35 * Brian Paul
36 */
37
38
39 #include "cell_batch.h"
40 #include "cell_context.h"
41 #include "cell_flush.h"
42 #include "cell_spu.h"
43 #include "cell_vbuf.h"
44 #include "draw/draw_vbuf.h"
45 #include "util/u_memory.h"
46
47
48 /** Allow vertex data to be inlined after RENDER command */
49 #define ALLOW_INLINE_VERTS 1
50
51
52 /**
53 * Subclass of vbuf_render because we need a cell_context pointer in
54 * a few places.
55 */
56 struct cell_vbuf_render
57 {
58 struct vbuf_render base;
59 struct cell_context *cell;
60 uint prim; /**< PIPE_PRIM_x */
61 uint vertex_size; /**< in bytes */
62 void *vertex_buffer; /**< just for debug, really */
63 uint vertex_buf; /**< in [0, CELL_NUM_BUFFERS-1] */
64 };
65
66
67 /** cast wrapper */
68 static struct cell_vbuf_render *
69 cell_vbuf_render(struct vbuf_render *vbr)
70 {
71 return (struct cell_vbuf_render *) vbr;
72 }
73
74
75
76 static const struct vertex_info *
77 cell_vbuf_get_vertex_info(struct vbuf_render *vbr)
78 {
79 struct cell_vbuf_render *cvbr = cell_vbuf_render(vbr);
80 return &cvbr->cell->vertex_info;
81 }
82
83
84 static void *
85 cell_vbuf_allocate_vertices(struct vbuf_render *vbr,
86 ushort vertex_size, ushort nr_vertices)
87 {
88 struct cell_vbuf_render *cvbr = cell_vbuf_render(vbr);
89 /*printf("Alloc verts %u * %u\n", vertex_size, nr_vertices);*/
90
91 assert(cvbr->vertex_buf == ~0);
92 cvbr->vertex_buf = cell_get_empty_buffer(cvbr->cell);
93 cvbr->vertex_buffer = cvbr->cell->buffer[cvbr->vertex_buf];
94 cvbr->vertex_size = vertex_size;
95 return cvbr->vertex_buffer;
96 }
97
98
99 static void
100 cell_vbuf_release_vertices(struct vbuf_render *vbr, void *vertices,
101 unsigned vertex_size, unsigned vertices_used)
102 {
103 struct cell_vbuf_render *cvbr = cell_vbuf_render(vbr);
104 struct cell_context *cell = cvbr->cell;
105
106 /*
107 printf("%s vertex_buf = %u count = %u\n",
108 __FUNCTION__, cvbr->vertex_buf, vertices_used);
109 */
110
111 /* Tell SPUs they can release the vert buf */
112 if (cvbr->vertex_buf != ~0U) {
113 struct cell_command_release_verts *release
114 = (struct cell_command_release_verts *)
115 cell_batch_alloc(cell, sizeof(struct cell_command_release_verts));
116 release->opcode = CELL_CMD_RELEASE_VERTS;
117 release->vertex_buf = cvbr->vertex_buf;
118 }
119
120 cvbr->vertex_buf = ~0;
121 cell_flush_int(cell, 0x0);
122
123 assert(vertices == cvbr->vertex_buffer);
124 cvbr->vertex_buffer = NULL;
125 }
126
127
128
129 static boolean
130 cell_vbuf_set_primitive(struct vbuf_render *vbr, unsigned prim)
131 {
132 struct cell_vbuf_render *cvbr = cell_vbuf_render(vbr);
133 cvbr->prim = prim;
134 /*printf("cell_set_prim %u\n", prim);*/
135 return TRUE;
136 }
137
138
139 static void
140 cell_vbuf_draw(struct vbuf_render *vbr,
141 const ushort *indices,
142 uint nr_indices)
143 {
144 struct cell_vbuf_render *cvbr = cell_vbuf_render(vbr);
145 struct cell_context *cell = cvbr->cell;
146 float xmin, ymin, xmax, ymax;
147 uint i;
148 uint nr_vertices = 0, min_index = ~0;
149 const void *vertices = cvbr->vertex_buffer;
150 const uint vertex_size = cvbr->vertex_size;
151
152 for (i = 0; i < nr_indices; i++) {
153 if (indices[i] > nr_vertices)
154 nr_vertices = indices[i];
155 if (indices[i] < min_index)
156 min_index = indices[i];
157 }
158 nr_vertices++;
159
160 #if 0
161 /*if (min_index > 0)*/
162 printf("%s min_index = %u\n", __FUNCTION__, min_index);
163 #endif
164
165 #if 0
166 printf("cell_vbuf_draw() nr_indices = %u nr_verts = %u\n",
167 nr_indices, nr_vertices);
168 printf(" ");
169 for (i = 0; i < nr_indices; i += 3) {
170 printf("%u %u %u, ", indices[i+0], indices[i+1], indices[i+2]);
171 }
172 printf("\n");
173 #elif 0
174 printf("cell_vbuf_draw() nr_indices = %u nr_verts = %u indexes = [%u %u %u ...]\n",
175 nr_indices, nr_vertices,
176 indices[0], indices[1], indices[2]);
177 printf("ind space = %u, vert space = %u, space = %u\n",
178 nr_indices * 2,
179 nr_vertices * 4 * cell->vertex_info.size,
180 cell_batch_free_space(cell));
181 #endif
182
183 /* compute x/y bounding box */
184 xmin = ymin = 1e50;
185 xmax = ymax = -1e50;
186 for (i = min_index; i < nr_vertices; i++) {
187 const float *v = (float *) ((ubyte *) vertices + i * vertex_size);
188 if (v[0] < xmin)
189 xmin = v[0];
190 if (v[0] > xmax)
191 xmax = v[0];
192 if (v[1] < ymin)
193 ymin = v[1];
194 if (v[1] > ymax)
195 ymax = v[1];
196 }
197 #if 0
198 printf("PPU Bounds %g, %g .. %g, %g\n", xmin, ymin, xmax, ymax);
199 fflush(stdout);
200 #endif
201
202 if (cvbr->prim != PIPE_PRIM_TRIANGLES)
203 return; /* only render tris for now */
204
205 /* build/insert batch RENDER command */
206 {
207 const uint index_bytes = ROUNDUP8(nr_indices * 2);
208 const uint vertex_bytes = nr_vertices * 4 * cell->vertex_info.size;
209 const uint batch_size = sizeof(struct cell_command_render) + index_bytes;
210
211 struct cell_command_render *render
212 = (struct cell_command_render *)
213 cell_batch_alloc(cell, batch_size);
214
215 render->opcode = CELL_CMD_RENDER;
216 render->prim_type = cvbr->prim;
217 render->front_winding = cell->rasterizer->front_winding;
218
219 render->num_indexes = nr_indices;
220 render->min_index = min_index;
221
222 /* append indices after render command */
223 memcpy(render + 1, indices, nr_indices * 2);
224
225 /* if there's room, append vertices after the indices, else leave
226 * vertices in the original/separate buffer.
227 */
228 render->vertex_size = 4 * cell->vertex_info.size;
229 render->num_verts = nr_vertices;
230 if (ALLOW_INLINE_VERTS &&
231 min_index == 0 &&
232 vertex_bytes + 16 <= cell_batch_free_space(cell)) {
233 /* vertex data inlined, after indices, at 16-byte boundary */
234 void *dst = cell_batch_alloc_aligned(cell, vertex_bytes, 16);
235 memcpy(dst, vertices, vertex_bytes);
236 render->inline_verts = TRUE;
237 render->vertex_buf = ~0;
238 }
239 else {
240 /* vertex data in separate buffer */
241 render->inline_verts = FALSE;
242 ASSERT(cvbr->vertex_buf >= 0);
243 render->vertex_buf = cvbr->vertex_buf;
244 }
245
246 render->xmin = xmin;
247 render->ymin = ymin;
248 render->xmax = xmax;
249 render->ymax = ymax;
250 }
251
252 #if 0
253 /* helpful for debug */
254 cell_flush_int(cell, CELL_FLUSH_WAIT);
255 #endif
256 }
257
258
259 static void
260 cell_vbuf_destroy(struct vbuf_render *vbr)
261 {
262 struct cell_vbuf_render *cvbr = cell_vbuf_render(vbr);
263 cvbr->cell->vbuf_render = NULL;
264 FREE(cvbr);
265 }
266
267
268 /**
269 * Initialize the post-transform vertex buffer information for the given
270 * context.
271 */
272 void
273 cell_init_vbuf(struct cell_context *cell)
274 {
275 assert(cell->draw);
276
277 cell->vbuf_render = CALLOC_STRUCT(cell_vbuf_render);
278
279 /* The max number of indexes is what can fix into a batch buffer,
280 * minus the render and release-verts commands.
281 */
282 cell->vbuf_render->base.max_indices
283 = (CELL_BUFFER_SIZE
284 - sizeof(struct cell_command_render)
285 - sizeof(struct cell_command_release_verts))
286 / sizeof(ushort);
287 cell->vbuf_render->base.max_vertex_buffer_bytes = CELL_BUFFER_SIZE;
288
289 cell->vbuf_render->base.get_vertex_info = cell_vbuf_get_vertex_info;
290 cell->vbuf_render->base.allocate_vertices = cell_vbuf_allocate_vertices;
291 cell->vbuf_render->base.set_primitive = cell_vbuf_set_primitive;
292 cell->vbuf_render->base.draw = cell_vbuf_draw;
293 cell->vbuf_render->base.release_vertices = cell_vbuf_release_vertices;
294 cell->vbuf_render->base.destroy = cell_vbuf_destroy;
295
296 cell->vbuf_render->cell = cell;
297 #if 1
298 cell->vbuf_render->vertex_buf = ~0;
299 #endif
300
301 cell->vbuf = draw_vbuf_stage(cell->draw, &cell->vbuf_render->base);
302 }