Tizen 2.0 Release
[profile/ivi/osmesa.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         struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
32
33         if (rs->prim != NV30_3D_VERTEX_BEGIN_END_STOP) {
34                 BEGIN_RING(chan, eng3d, 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         struct nouveau_grobj *eng3d = screen->eng3d;
50         boolean no_elements = nvfx->vertprog->draw_no_elements;
51         unsigned num_attribs = nvfx->vertprog->draw_elements;
52
53         /* we need to account the flush as well here even if it is done afterthis
54          * function
55          */
56         if (AVAIL_RING(chan) < ((1 + count * num_attribs * 4) + 6 + 64)) {
57                 nvfx_render_flush(stage, 0);
58                 FIRE_RING(chan);
59                 nvfx_state_emit(nvfx);
60
61                 assert(AVAIL_RING(chan) >= ((1 + count * num_attribs * 4) + 6 + 64));
62         }
63
64         /* Switch primitive modes if necessary */
65         if (rs->prim != mode) {
66                 if (rs->prim != NV30_3D_VERTEX_BEGIN_END_STOP) {
67                         BEGIN_RING(chan, eng3d, NV30_3D_VERTEX_BEGIN_END, 1);
68                         OUT_RING(chan, NV30_3D_VERTEX_BEGIN_END_STOP);
69                 }
70
71                 /* XXX: any command a lot of times seems to (mostly) fix corruption that would otherwise happen */
72                 /* this seems to cause issues on nv3x, and also be unneeded there */
73                 if(nvfx->is_nv4x)
74                 {
75                         int i;
76                         for(i = 0; i < 32; ++i)
77                         {
78                                 BEGIN_RING(chan, eng3d, 0x1dac, 1);
79                                 OUT_RING(chan, 0);
80                         }
81                 }
82
83                 BEGIN_RING(chan, eng3d, NV30_3D_VERTEX_BEGIN_END, 1);
84                 OUT_RING  (chan, mode);
85                 rs->prim = mode;
86         }
87
88         if(no_elements) {
89                 BEGIN_RING_NI(chan, eng3d, NV30_3D_VERTEX_DATA, 4);
90                 OUT_RING(chan, 0);
91                 OUT_RING(chan, 0);
92                 OUT_RING(chan, 0);
93                 OUT_RING(chan, 0);
94         } else {
95                 BEGIN_RING_NI(chan, eng3d, NV30_3D_VERTEX_DATA, num_attribs * 4 * count);
96                 for (unsigned i = 0; i < count; ++i)
97                 {
98                         struct vertex_header* v = prim->v[i];
99                         /* TODO: disable divide where it's causing the problem, and remove this hack */
100                         OUT_RING(chan, fui(v->data[0][0] / v->data[0][3]));
101                         OUT_RING(chan, fui(v->data[0][1] / v->data[0][3]));
102                         OUT_RING(chan, fui(v->data[0][2] / v->data[0][3]));
103                         OUT_RING(chan, fui(1.0f / v->data[0][3]));
104                         OUT_RINGp(chan, &v->data[1][0], 4 * (num_attribs - 1));
105                 }
106         }
107 }
108
109 static void
110 nvfx_render_point(struct draw_stage *draw, struct prim_header *prim)
111 {
112         nvfx_render_prim(draw, prim, NV30_3D_VERTEX_BEGIN_END_POINTS, 1);
113 }
114
115 static void
116 nvfx_render_line(struct draw_stage *draw, struct prim_header *prim)
117 {
118         nvfx_render_prim(draw, prim, NV30_3D_VERTEX_BEGIN_END_LINES, 2);
119 }
120
121 static void
122 nvfx_render_tri(struct draw_stage *draw, struct prim_header *prim)
123 {
124         nvfx_render_prim(draw, prim, NV30_3D_VERTEX_BEGIN_END_TRIANGLES, 3);
125 }
126
127 static void
128 nvfx_render_reset_stipple_counter(struct draw_stage *draw)
129 {
130         /* this doesn't really seem to work, but it matters rather little */
131         nvfx_render_flush(draw, 0);
132 }
133
134 static void
135 nvfx_render_destroy(struct draw_stage *draw)
136 {
137         FREE(draw);
138 }
139
140 struct draw_stage *
141 nvfx_draw_render_stage(struct nvfx_context *nvfx)
142 {
143         struct nvfx_render_stage *render = CALLOC_STRUCT(nvfx_render_stage);
144
145         render->nvfx = nvfx;
146         render->stage.draw = nvfx->draw;
147         render->stage.point = nvfx_render_point;
148         render->stage.line = nvfx_render_line;
149         render->stage.tri = nvfx_render_tri;
150         render->stage.flush = nvfx_render_flush;
151         render->stage.reset_stipple_counter = nvfx_render_reset_stipple_counter;
152         render->stage.destroy = nvfx_render_destroy;
153
154         return &render->stage;
155 }
156
157 void
158 nvfx_draw_vbo_swtnl(struct pipe_context *pipe, const struct pipe_draw_info* info)
159 {
160         struct nvfx_context *nvfx = nvfx_context(pipe);
161         unsigned i;
162         void *map;
163
164         if (!nvfx_state_validate_swtnl(nvfx))
165                 return;
166
167         nvfx_state_emit(nvfx);
168
169         /* these must be passed without adding the offsets */
170         for (i = 0; i < nvfx->vtxbuf_nr; i++) {
171                 map = nvfx_buffer(nvfx->vtxbuf[i].buffer)->data;
172                 draw_set_mapped_vertex_buffer(nvfx->draw, i, map);
173         }
174
175         map = NULL;
176         if (info->indexed && nvfx->idxbuf.buffer)
177                 map = nvfx_buffer(nvfx->idxbuf.buffer)->data;
178         draw_set_mapped_index_buffer(nvfx->draw, map);
179
180         if (nvfx->constbuf[PIPE_SHADER_VERTEX]) {
181                 const unsigned nr = nvfx->constbuf_nr[PIPE_SHADER_VERTEX];
182
183                 map = nvfx_buffer(nvfx->constbuf[PIPE_SHADER_VERTEX])->data;
184                 draw_set_mapped_constant_buffer(nvfx->draw, PIPE_SHADER_VERTEX, 0,
185                                                 map, nr);
186         }
187
188         draw_vbo(nvfx->draw, info);
189
190         draw_flush(nvfx->draw);
191 }