nv40: insanely stupid bug..
[mesa.git] / src / mesa / pipe / nv40 / nv40_vbo.c
1 #include "pipe/p_context.h"
2 #include "pipe/p_state.h"
3 #include "pipe/p_util.h"
4
5 #include "nv40_context.h"
6 #include "nv40_dma.h"
7 #include "nv40_state.h"
8
9 boolean
10 nv40_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
11 unsigned count)
12 {
13 struct nv40_context *nv40 = (struct nv40_context *)pipe;
14 unsigned nr;
15
16 if (nv40->dirty)
17 nv40_emit_hw_state(nv40);
18
19 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
20 OUT_RING (nvgl_primitive(mode));
21
22 nr = (count & 0xff);
23 if (nr) {
24 BEGIN_RING(curie, NV40TCL_VB_VERTEX_BATCH, 1);
25 OUT_RING (((nr - 1) << 24) | start);
26 start += nr;
27 }
28
29 /*XXX: large arrays (nr>2047) will blow up */
30 nr = count >> 8;
31 if (nr) {
32 assert (nr <= 2047);
33
34 BEGIN_RING_NI(curie, NV40TCL_VB_VERTEX_BATCH, nr);
35 while (nr--) {
36 OUT_RING(((0x100 - 1) << 24) | start);
37 start += 0x100;
38 }
39 }
40
41 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
42 OUT_RING (0);
43
44 pipe->flush(pipe, 0);
45 return TRUE;
46 }
47
48 static INLINE void
49 nv40_draw_elements_u08(struct nv40_context *nv40, void *ib,
50 unsigned start, unsigned count)
51 {
52 uint8_t *elts = (uint8_t *)ib + start;
53 int push, i;
54
55 if (count & 1) {
56 BEGIN_RING(curie, NV40TCL_VB_ELEMENT_U32, 1);
57 OUT_RING (elts[0]);
58 elts++; count--;
59 }
60
61 while (count) {
62 push = MIN2(count, 2046);
63
64 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U16, push);
65 for (i = 0; i < push; i+=2)
66 OUT_RING((elts[i+1] << 16) | elts[i]);
67
68 count -= push;
69 elts += push;
70 }
71 }
72
73 static INLINE void
74 nv40_draw_elements_u16(struct nv40_context *nv40, void *ib,
75 unsigned start, unsigned count)
76 {
77 uint16_t *elts = (uint16_t *)ib + start;
78 int push, i;
79
80 if (count & 1) {
81 BEGIN_RING(curie, NV40TCL_VB_ELEMENT_U32, 1);
82 OUT_RING (elts[0]);
83 elts++; count--;
84 }
85
86 while (count) {
87 push = MIN2(count, 2046);
88
89 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U16, push);
90 for (i = 0; i < push; i+=2)
91 OUT_RING((elts[i+1] << 16) | elts[i]);
92
93 count -= push;
94 elts += push;
95 }
96 }
97
98 static INLINE void
99 nv40_draw_elements_u32(struct nv40_context *nv40, void *ib,
100 unsigned start, unsigned count)
101 {
102 uint32_t *elts = (uint32_t *)ib + start;
103 int push;
104
105 while (count) {
106 push = MIN2(count, 2047);
107
108 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U32, push);
109 OUT_RINGp (elts, push);
110
111 count -= push;
112 elts += push;
113 }
114 }
115
116 boolean
117 nv40_draw_elements(struct pipe_context *pipe,
118 struct pipe_buffer_handle *indexBuffer, unsigned indexSize,
119 unsigned mode, unsigned start, unsigned count)
120 {
121 struct nv40_context *nv40 = (struct nv40_context *)pipe;
122 void *ib;
123
124 if (nv40->dirty)
125 nv40_emit_hw_state(nv40);
126
127 ib = pipe->winsys->buffer_map(pipe->winsys, indexBuffer,
128 PIPE_BUFFER_FLAG_READ);
129 if (!ib) {
130 NOUVEAU_ERR("Couldn't map index buffer!!\n");
131 return FALSE;
132 }
133
134 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
135 OUT_RING (nvgl_primitive(mode));
136
137 switch (indexSize) {
138 case 1:
139 nv40_draw_elements_u08(nv40, ib, start, count);
140 break;
141 case 2:
142 nv40_draw_elements_u16(nv40, ib, start, count);
143 break;
144 case 4:
145 nv40_draw_elements_u32(nv40, ib, start, count);
146 break;
147 default:
148 NOUVEAU_ERR("unsupported elt size %d\n", indexSize);
149 break;
150 }
151
152 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
153 OUT_RING (0);
154
155 pipe->winsys->buffer_unmap(pipe->winsys, indexBuffer);
156 pipe->flush(pipe, 0);
157 return TRUE;
158 }
159
160 static INLINE int
161 nv40_vbo_ncomp(uint format)
162 {
163 int ncomp = 0;
164
165 if (pf_size_x(format)) ncomp++;
166 if (pf_size_y(format)) ncomp++;
167 if (pf_size_z(format)) ncomp++;
168 if (pf_size_w(format)) ncomp++;
169
170 return ncomp;
171 }
172
173 static INLINE int
174 nv40_vbo_type(uint format)
175 {
176 switch (pf_type(format)) {
177 case PIPE_FORMAT_TYPE_FLOAT:
178 return NV40TCL_VTXFMT_TYPE_FLOAT;
179 case PIPE_FORMAT_TYPE_UNORM:
180 return NV40TCL_VTXFMT_TYPE_UBYTE;
181 default:
182 assert(0);
183 }
184 }
185
186 void
187 nv40_vbo_arrays_update(struct nv40_context *nv40)
188 {
189 struct nv40_vertex_program *vp = nv40->vertprog.active;
190 uint32_t inputs, vtxfmt[16];
191 int hw, num_hw;
192
193 inputs = vp->ir;
194 for (hw = 0; hw < 16 && inputs; hw++) {
195 if (inputs & (1 << hw)) {
196 num_hw = hw;
197 inputs &= ~(1 << hw);
198 }
199 }
200 num_hw++;
201
202 inputs = vp->ir;
203 BEGIN_RING(curie, NV40TCL_VTXBUF_ADDRESS(0), num_hw);
204 for (hw = 0; hw < num_hw; hw++) {
205 struct pipe_vertex_element *ve;
206 struct pipe_vertex_buffer *vb;
207
208 if (!(inputs & (1 << hw))) {
209 OUT_RING(0);
210 vtxfmt[hw] = NV40TCL_VTXFMT_TYPE_FLOAT;
211 continue;
212 }
213
214 ve = &nv40->vtxelt[hw];
215 vb = &nv40->vtxbuf[ve->vertex_buffer_index];
216
217 OUT_RELOC(vb->buffer, vb->buffer_offset + ve->src_offset,
218 NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_LOW |
219 NOUVEAU_BO_OR | NOUVEAU_BO_RD, 0,
220 NV40TCL_VTXBUF_ADDRESS_DMA1);
221 vtxfmt[hw] = ((vb->pitch << NV40TCL_VTXFMT_STRIDE_SHIFT) |
222 (nv40_vbo_ncomp(ve->src_format) <<
223 NV40TCL_VTXFMT_SIZE_SHIFT) |
224 nv40_vbo_type(ve->src_format));
225 }
226
227 BEGIN_RING(curie, 0x1710, 1);
228 OUT_RING (0); /* vtx cache flush */
229 BEGIN_RING(curie, NV40TCL_VTXFMT(0), num_hw);
230 OUT_RINGp (vtxfmt, num_hw);
231 }
232