Merge remote branch 'origin/master' into nv50-compiler
[mesa.git] / src / gallium / drivers / nvfx / nvfx_draw.c
1 #include "pipe/p_shader_tokens.h"
2 #include "util/u_inlines.h"
3 #include "tgsi/tgsi_ureg.h"
4
5 #include "util/u_pack_color.h"
6
7 #include "draw/draw_context.h"
8 #include "draw/draw_vertex.h"
9 #include "draw/draw_pipe.h"
10
11 #include "nvfx_context.h"
12 #include "nvfx_resource.h"
13
14 /* Simple, but crappy, swtnl path, hopefully we wont need to hit this very
15 * often at all. Uses "quadro style" vertex submission + a fixed vertex
16 * layout to avoid the need to generate a vertex program or vtxfmt.
17 */
18
19 struct nvfx_render_stage {
20 struct draw_stage stage;
21 struct nvfx_context *nvfx;
22 unsigned prim;
23 };
24
25 static INLINE struct nvfx_render_stage *
26 nvfx_render_stage(struct draw_stage *stage)
27 {
28 return (struct nvfx_render_stage *)stage;
29 }
30
31 static INLINE void
32 nvfx_render_vertex(struct nvfx_context *nvfx, const struct vertex_header *v)
33 {
34 struct nvfx_screen *screen = nvfx->screen;
35 struct nouveau_channel *chan = screen->base.channel;
36 struct nouveau_grobj *eng3d = screen->eng3d;
37 unsigned i;
38
39 for (i = 0; i < nvfx->swtnl.nr_attribs; i++) {
40 unsigned idx = nvfx->swtnl.draw[i];
41 unsigned hw = nvfx->swtnl.hw[i];
42
43 WAIT_RING(chan, 5);
44 switch (nvfx->swtnl.emit[i]) {
45 case EMIT_OMIT:
46 break;
47 case EMIT_1F:
48 nvfx_emit_vtx_attr(chan, hw, v->data[idx], 1);
49 break;
50 case EMIT_2F:
51 nvfx_emit_vtx_attr(chan, hw, v->data[idx], 2);
52 break;
53 case EMIT_3F:
54 nvfx_emit_vtx_attr(chan, hw, v->data[idx], 3);
55 break;
56 case EMIT_4F:
57 nvfx_emit_vtx_attr(chan, hw, v->data[idx], 4);
58 break;
59 case 0xff:
60 BEGIN_RING(chan, eng3d, NV34TCL_VTX_ATTR_4F_X(hw), 4);
61 OUT_RING (chan, fui(v->data[idx][0] / v->data[idx][3]));
62 OUT_RING (chan, fui(v->data[idx][1] / v->data[idx][3]));
63 OUT_RING (chan, fui(v->data[idx][2] / v->data[idx][3]));
64 OUT_RING (chan, fui(1.0f / v->data[idx][3]));
65 break;
66 case EMIT_4UB:
67 BEGIN_RING(chan, eng3d, NV34TCL_VTX_ATTR_4UB(hw), 1);
68 OUT_RING (chan, pack_ub4(float_to_ubyte(v->data[idx][0]),
69 float_to_ubyte(v->data[idx][1]),
70 float_to_ubyte(v->data[idx][2]),
71 float_to_ubyte(v->data[idx][3])));
72 case EMIT_4UB_BGRA:
73 BEGIN_RING(chan, eng3d, NV34TCL_VTX_ATTR_4UB(hw), 1);
74 OUT_RING (chan, pack_ub4(float_to_ubyte(v->data[idx][2]),
75 float_to_ubyte(v->data[idx][1]),
76 float_to_ubyte(v->data[idx][0]),
77 float_to_ubyte(v->data[idx][3])));
78 break;
79 default:
80 assert(0);
81 break;
82 }
83 }
84 }
85
86 static INLINE void
87 nvfx_render_prim(struct draw_stage *stage, struct prim_header *prim,
88 unsigned mode, unsigned count)
89 {
90 struct nvfx_render_stage *rs = nvfx_render_stage(stage);
91 struct nvfx_context *nvfx = rs->nvfx;
92
93 struct nvfx_screen *screen = nvfx->screen;
94 struct nouveau_channel *chan = screen->base.channel;
95 struct nouveau_grobj *eng3d = screen->eng3d;
96 unsigned i;
97
98 /* Ensure there's room for 4xfloat32 + potentially 3 begin/end */
99 if (AVAIL_RING(chan) < ((count * 20) + 6)) {
100 if (rs->prim != NV34TCL_VERTEX_BEGIN_END_STOP) {
101 NOUVEAU_ERR("AIII, missed flush\n");
102 assert(0);
103 }
104 FIRE_RING(chan);
105 nvfx_state_emit(nvfx);
106 }
107
108 /* Switch primitive modes if necessary */
109 if (rs->prim != mode) {
110 if (rs->prim != NV34TCL_VERTEX_BEGIN_END_STOP) {
111 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
112 OUT_RING (chan, NV34TCL_VERTEX_BEGIN_END_STOP);
113 }
114
115 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
116 OUT_RING (chan, mode);
117 rs->prim = mode;
118 }
119
120 /* Emit vertex data */
121 for (i = 0; i < count; i++)
122 nvfx_render_vertex(nvfx, prim->v[i]);
123
124 /* If it's likely we'll need to empty the push buffer soon, finish
125 * off the primitive now.
126 */
127 if (AVAIL_RING(chan) < ((count * 20) + 6)) {
128 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
129 OUT_RING (chan, NV34TCL_VERTEX_BEGIN_END_STOP);
130 rs->prim = NV34TCL_VERTEX_BEGIN_END_STOP;
131 }
132 }
133
134 static void
135 nvfx_render_point(struct draw_stage *draw, struct prim_header *prim)
136 {
137 nvfx_render_prim(draw, prim, NV34TCL_VERTEX_BEGIN_END_POINTS, 1);
138 }
139
140 static void
141 nvfx_render_line(struct draw_stage *draw, struct prim_header *prim)
142 {
143 nvfx_render_prim(draw, prim, NV34TCL_VERTEX_BEGIN_END_LINES, 2);
144 }
145
146 static void
147 nvfx_render_tri(struct draw_stage *draw, struct prim_header *prim)
148 {
149 nvfx_render_prim(draw, prim, NV34TCL_VERTEX_BEGIN_END_TRIANGLES, 3);
150 }
151
152 static void
153 nvfx_render_flush(struct draw_stage *draw, unsigned flags)
154 {
155 struct nvfx_render_stage *rs = nvfx_render_stage(draw);
156 struct nvfx_context *nvfx = rs->nvfx;
157 struct nvfx_screen *screen = nvfx->screen;
158 struct nouveau_channel *chan = screen->base.channel;
159 struct nouveau_grobj *eng3d = screen->eng3d;
160
161 if (rs->prim != NV34TCL_VERTEX_BEGIN_END_STOP) {
162 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
163 OUT_RING (chan, NV34TCL_VERTEX_BEGIN_END_STOP);
164 rs->prim = NV34TCL_VERTEX_BEGIN_END_STOP;
165 }
166 }
167
168 static void
169 nvfx_render_reset_stipple_counter(struct draw_stage *draw)
170 {
171 }
172
173 static void
174 nvfx_render_destroy(struct draw_stage *draw)
175 {
176 FREE(draw);
177 }
178
179 static struct nvfx_vertex_program *
180 nvfx_create_drawvp(struct nvfx_context *nvfx)
181 {
182 struct ureg_program *ureg;
183 uint i;
184
185 ureg = ureg_create( TGSI_PROCESSOR_VERTEX );
186 if (ureg == NULL)
187 return NULL;
188
189 ureg_MOV(ureg, ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0), ureg_DECL_vs_input(ureg, 0));
190 ureg_MOV(ureg, ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0), ureg_DECL_vs_input(ureg, 3));
191 ureg_MOV(ureg, ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 1), ureg_DECL_vs_input(ureg, 4));
192 ureg_MOV(ureg, ureg_DECL_output(ureg, TGSI_SEMANTIC_BCOLOR, 0), ureg_DECL_vs_input(ureg, 3));
193 ureg_MOV(ureg, ureg_DECL_output(ureg, TGSI_SEMANTIC_BCOLOR, 1), ureg_DECL_vs_input(ureg, 4));
194 ureg_MOV(ureg,
195 ureg_writemask(ureg_DECL_output(ureg, TGSI_SEMANTIC_FOG, 1), TGSI_WRITEMASK_X),
196 ureg_DECL_vs_input(ureg, 5));
197 for (i = 0; i < 8; ++i)
198 ureg_MOV(ureg, ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, i), ureg_DECL_vs_input(ureg, 8 + i));
199
200 ureg_END( ureg );
201
202 return ureg_create_shader_and_destroy( ureg, &nvfx->pipe );
203 }
204
205 struct draw_stage *
206 nvfx_draw_render_stage(struct nvfx_context *nvfx)
207 {
208 struct nvfx_render_stage *render = CALLOC_STRUCT(nvfx_render_stage);
209
210 if (!nvfx->swtnl.vertprog)
211 nvfx->swtnl.vertprog = nvfx_create_drawvp(nvfx);
212
213 render->nvfx = nvfx;
214 render->stage.draw = nvfx->draw;
215 render->stage.point = nvfx_render_point;
216 render->stage.line = nvfx_render_line;
217 render->stage.tri = nvfx_render_tri;
218 render->stage.flush = nvfx_render_flush;
219 render->stage.reset_stipple_counter = nvfx_render_reset_stipple_counter;
220 render->stage.destroy = nvfx_render_destroy;
221
222 return &render->stage;
223 }
224
225 void
226 nvfx_draw_vbo_swtnl(struct pipe_context *pipe, const struct pipe_draw_info* info)
227 {
228 struct nvfx_context *nvfx = nvfx_context(pipe);
229 unsigned i;
230 void *map;
231
232 if (!nvfx_state_validate_swtnl(nvfx))
233 return;
234 nvfx_state_emit(nvfx);
235
236 /* these must be passed without adding the offsets */
237 for (i = 0; i < nvfx->vtxbuf_nr; i++) {
238 map = nvfx_buffer(nvfx->vtxbuf[i].buffer)->data;
239 draw_set_mapped_vertex_buffer(nvfx->draw, i, map);
240 }
241
242 map = NULL;
243 if (info->indexed && nvfx->idxbuf.buffer)
244 map = nvfx_buffer(nvfx->idxbuf.buffer)->data;
245 draw_set_mapped_index_buffer(nvfx->draw, map);
246
247 if (nvfx->constbuf[PIPE_SHADER_VERTEX]) {
248 const unsigned nr = nvfx->constbuf_nr[PIPE_SHADER_VERTEX];
249
250 map = nvfx_buffer(nvfx->constbuf[PIPE_SHADER_VERTEX])->data;
251 draw_set_mapped_constant_buffer(nvfx->draw, PIPE_SHADER_VERTEX, 0,
252 map, nr);
253 }
254
255 draw_vbo(nvfx->draw, info);
256
257 draw_flush(nvfx->draw);
258 }
259
260 static INLINE void
261 emit_attrib(struct nvfx_context *nvfx, unsigned hw, unsigned emit,
262 unsigned semantic, unsigned index)
263 {
264 unsigned draw_out = draw_find_shader_output(nvfx->draw, semantic, index);
265 unsigned a = nvfx->swtnl.nr_attribs++;
266
267 nvfx->swtnl.hw[a] = hw;
268 nvfx->swtnl.emit[a] = emit;
269 nvfx->swtnl.draw[a] = draw_out;
270 }
271
272 void
273 nvfx_vtxfmt_validate(struct nvfx_context *nvfx)
274 {
275 struct nvfx_pipe_fragment_program *pfp = nvfx->fragprog;
276 unsigned colour = 0, texcoords = 0, fog = 0, i;
277
278 /* Determine needed fragprog inputs */
279 for (i = 0; i < pfp->info.num_inputs; i++) {
280 switch (pfp->info.input_semantic_name[i]) {
281 case TGSI_SEMANTIC_POSITION:
282 break;
283 case TGSI_SEMANTIC_COLOR:
284 colour |= (1 << pfp->info.input_semantic_index[i]);
285 break;
286 case TGSI_SEMANTIC_GENERIC:
287 texcoords |= (1 << pfp->info.input_semantic_index[i]);
288 break;
289 case TGSI_SEMANTIC_FOG:
290 fog = 1;
291 break;
292 default:
293 assert(0);
294 }
295 }
296
297 nvfx->swtnl.nr_attribs = 0;
298
299 /* Map draw vtxprog output to hw attribute IDs */
300 for (i = 0; i < 2; i++) {
301 if (!(colour & (1 << i)))
302 continue;
303 emit_attrib(nvfx, 3 + i, EMIT_4F, TGSI_SEMANTIC_COLOR, i);
304 }
305
306 for (i = 0; i < 8; i++) {
307 if (!(texcoords & (1 << i)))
308 continue;
309 emit_attrib(nvfx, 8 + i, EMIT_4F, TGSI_SEMANTIC_GENERIC, i);
310 }
311
312 if (fog) {
313 emit_attrib(nvfx, 5, EMIT_1F, TGSI_SEMANTIC_FOG, 0);
314 }
315
316 emit_attrib(nvfx, 0, 0xff, TGSI_SEMANTIC_POSITION, 0);
317 }