docs: Update status of GL 3.x related extensions
[mesa.git] / src / gallium / drivers / nvfx / nvfx_draw.c
1 #include "pipe/p_shader_tokens.h"
2 #include "util/u_inlines.h"
3
4 #include "util/u_pack_color.h"
5
6 #include "draw/draw_context.h"
7 #include "draw/draw_vertex.h"
8 #include "draw/draw_pipe.h"
9
10 #include "nvfx_context.h"
11 #include "nvfx_resource.h"
12
13 struct nvfx_render_stage {
14 struct draw_stage stage;
15 struct nvfx_context *nvfx;
16 unsigned prim;
17 };
18
19 static INLINE struct nvfx_render_stage *
20 nvfx_render_stage(struct draw_stage *stage)
21 {
22 return (struct nvfx_render_stage *)stage;
23 }
24
25 static void
26 nvfx_render_flush(struct draw_stage *stage, unsigned flags)
27 {
28 struct nvfx_render_stage *rs = nvfx_render_stage(stage);
29 struct nvfx_context *nvfx = rs->nvfx;
30 struct nouveau_channel *chan = nvfx->screen->base.channel;
31
32 if (rs->prim != NV30_3D_VERTEX_BEGIN_END_STOP) {
33 assert(AVAIL_RING(chan) >= 2);
34 OUT_RING(chan, RING_3D(NV30_3D_VERTEX_BEGIN_END, 1));
35 OUT_RING(chan, NV30_3D_VERTEX_BEGIN_END_STOP);
36 rs->prim = NV30_3D_VERTEX_BEGIN_END_STOP;
37 }
38 }
39
40 static INLINE void
41 nvfx_render_prim(struct draw_stage *stage, struct prim_header *prim,
42 unsigned mode, unsigned count)
43 {
44 struct nvfx_render_stage *rs = nvfx_render_stage(stage);
45 struct nvfx_context *nvfx = rs->nvfx;
46
47 struct nvfx_screen *screen = nvfx->screen;
48 struct nouveau_channel *chan = screen->base.channel;
49 boolean no_elements = nvfx->vertprog->draw_no_elements;
50 unsigned num_attribs = nvfx->vertprog->draw_elements;
51
52 /* we need to account the flush as well here even if it is done afterthis
53 * function
54 */
55 if (AVAIL_RING(chan) < ((1 + count * num_attribs * 4) + 6 + 64)) {
56 nvfx_render_flush(stage, 0);
57 FIRE_RING(chan);
58 nvfx_state_emit(nvfx);
59
60 assert(AVAIL_RING(chan) >= ((1 + count * num_attribs * 4) + 6 + 64));
61 }
62
63 /* Switch primitive modes if necessary */
64 if (rs->prim != mode) {
65 if (rs->prim != NV30_3D_VERTEX_BEGIN_END_STOP) {
66 OUT_RING(chan, RING_3D(NV30_3D_VERTEX_BEGIN_END, 1));
67 OUT_RING(chan, NV30_3D_VERTEX_BEGIN_END_STOP);
68 }
69
70 /* XXX: any command a lot of times seems to (mostly) fix corruption that would otherwise happen */
71 /* this seems to cause issues on nv3x, and also be unneeded there */
72 if(nvfx->is_nv4x)
73 {
74 int i;
75 for(i = 0; i < 32; ++i)
76 {
77 OUT_RING(chan, RING_3D(0x1dac, 1));
78 OUT_RING(chan, 0);
79 }
80 }
81
82 OUT_RING(chan, RING_3D(NV30_3D_VERTEX_BEGIN_END, 1));
83 OUT_RING (chan, mode);
84 rs->prim = mode;
85 }
86
87 OUT_RING(chan, RING_3D_NI(NV30_3D_VERTEX_DATA, num_attribs * 4 * count));
88 if(no_elements) {
89 OUT_RING(chan, 0);
90 OUT_RING(chan, 0);
91 OUT_RING(chan, 0);
92 OUT_RING(chan, 0);
93 } else {
94 for (unsigned i = 0; i < count; ++i)
95 {
96 struct vertex_header* v = prim->v[i];
97 /* TODO: disable divide where it's causing the problem, and remove this hack */
98 OUT_RING(chan, fui(v->data[0][0] / v->data[0][3]));
99 OUT_RING(chan, fui(v->data[0][1] / v->data[0][3]));
100 OUT_RING(chan, fui(v->data[0][2] / v->data[0][3]));
101 OUT_RING(chan, fui(1.0f / v->data[0][3]));
102 OUT_RINGp(chan, &v->data[1][0], 4 * (num_attribs - 1));
103 }
104 }
105 }
106
107 static void
108 nvfx_render_point(struct draw_stage *draw, struct prim_header *prim)
109 {
110 nvfx_render_prim(draw, prim, NV30_3D_VERTEX_BEGIN_END_POINTS, 1);
111 }
112
113 static void
114 nvfx_render_line(struct draw_stage *draw, struct prim_header *prim)
115 {
116 nvfx_render_prim(draw, prim, NV30_3D_VERTEX_BEGIN_END_LINES, 2);
117 }
118
119 static void
120 nvfx_render_tri(struct draw_stage *draw, struct prim_header *prim)
121 {
122 nvfx_render_prim(draw, prim, NV30_3D_VERTEX_BEGIN_END_TRIANGLES, 3);
123 }
124
125 static void
126 nvfx_render_reset_stipple_counter(struct draw_stage *draw)
127 {
128 /* this doesn't really seem to work, but it matters rather little */
129 nvfx_render_flush(draw, 0);
130 }
131
132 static void
133 nvfx_render_destroy(struct draw_stage *draw)
134 {
135 FREE(draw);
136 }
137
138 struct draw_stage *
139 nvfx_draw_render_stage(struct nvfx_context *nvfx)
140 {
141 struct nvfx_render_stage *render = CALLOC_STRUCT(nvfx_render_stage);
142
143 render->nvfx = nvfx;
144 render->stage.draw = nvfx->draw;
145 render->stage.point = nvfx_render_point;
146 render->stage.line = nvfx_render_line;
147 render->stage.tri = nvfx_render_tri;
148 render->stage.flush = nvfx_render_flush;
149 render->stage.reset_stipple_counter = nvfx_render_reset_stipple_counter;
150 render->stage.destroy = nvfx_render_destroy;
151
152 return &render->stage;
153 }
154
155 void
156 nvfx_draw_vbo_swtnl(struct pipe_context *pipe, const struct pipe_draw_info* info)
157 {
158 struct nvfx_context *nvfx = nvfx_context(pipe);
159 unsigned i;
160 void *map;
161
162 if (!nvfx_state_validate_swtnl(nvfx))
163 return;
164
165 nvfx_state_emit(nvfx);
166
167 /* these must be passed without adding the offsets */
168 for (i = 0; i < nvfx->vtxbuf_nr; i++) {
169 map = nvfx_buffer(nvfx->vtxbuf[i].buffer)->data;
170 draw_set_mapped_vertex_buffer(nvfx->draw, i, map);
171 }
172
173 map = NULL;
174 if (info->indexed && nvfx->idxbuf.buffer)
175 map = nvfx_buffer(nvfx->idxbuf.buffer)->data;
176 draw_set_mapped_index_buffer(nvfx->draw, map);
177
178 if (nvfx->constbuf[PIPE_SHADER_VERTEX]) {
179 const unsigned nr = nvfx->constbuf_nr[PIPE_SHADER_VERTEX];
180
181 map = nvfx_buffer(nvfx->constbuf[PIPE_SHADER_VERTEX])->data;
182 draw_set_mapped_constant_buffer(nvfx->draw, PIPE_SHADER_VERTEX, 0,
183 map, nr);
184 }
185
186 draw_vbo(nvfx->draw, info);
187
188 draw_flush(nvfx->draw);
189 }