util: Move gallium's PIPE_FORMAT utils to /util/format/
[mesa.git] / src / gallium / drivers / nouveau / nv30 / nv30_push.c
1 /*
2 * Copyright 2012 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 *
24 */
25
26 #include "pipe/p_context.h"
27 #include "pipe/p_state.h"
28 #include "util/u_inlines.h"
29 #include "util/format/u_format.h"
30 #include "translate/translate.h"
31
32 #include "nv_object.xml.h"
33 #include "nv30/nv30-40_3d.xml.h"
34 #include "nv30/nv30_context.h"
35 #include "nv30/nv30_resource.h"
36
37 struct push_context {
38 struct nouveau_pushbuf *push;
39
40 const void *idxbuf;
41
42 float edgeflag;
43 int edgeflag_attr;
44
45 uint32_t vertex_words;
46 uint32_t packet_vertex_limit;
47
48 struct translate *translate;
49
50 bool primitive_restart;
51 uint32_t prim;
52 uint32_t restart_index;
53 };
54
55 static inline unsigned
56 prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index)
57 {
58 unsigned i;
59 for (i = 0; i < push; ++i)
60 if (elts[i] == index)
61 break;
62 return i;
63 }
64
65 static inline unsigned
66 prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index)
67 {
68 unsigned i;
69 for (i = 0; i < push; ++i)
70 if (elts[i] == index)
71 break;
72 return i;
73 }
74
75 static inline unsigned
76 prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index)
77 {
78 unsigned i;
79 for (i = 0; i < push; ++i)
80 if (elts[i] == index)
81 break;
82 return i;
83 }
84
85 static void
86 emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count)
87 {
88 uint8_t *elts = (uint8_t *)ctx->idxbuf + start;
89
90 while (count) {
91 unsigned push = MIN2(count, ctx->packet_vertex_limit);
92 unsigned size, nr;
93
94 nr = push;
95 if (ctx->primitive_restart)
96 nr = prim_restart_search_i08(elts, push, ctx->restart_index);
97
98 size = ctx->vertex_words * nr;
99
100 BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size);
101
102 ctx->translate->run_elts8(ctx->translate, elts, nr, 0, 0, ctx->push->cur);
103
104 ctx->push->cur += size;
105 count -= nr;
106 elts += nr;
107
108 if (nr != push) {
109 BEGIN_NV04(ctx->push, NV30_3D(VB_ELEMENT_U32), 1);
110 PUSH_DATA (ctx->push, ctx->restart_index);
111 count--;
112 elts++;
113 }
114 }
115 }
116
117 static void
118 emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count)
119 {
120 uint16_t *elts = (uint16_t *)ctx->idxbuf + start;
121
122 while (count) {
123 unsigned push = MIN2(count, ctx->packet_vertex_limit);
124 unsigned size, nr;
125
126 nr = push;
127 if (ctx->primitive_restart)
128 nr = prim_restart_search_i16(elts, push, ctx->restart_index);
129
130 size = ctx->vertex_words * nr;
131
132 BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size);
133
134 ctx->translate->run_elts16(ctx->translate, elts, nr, 0, 0, ctx->push->cur);
135
136 ctx->push->cur += size;
137 count -= nr;
138 elts += nr;
139
140 if (nr != push) {
141 BEGIN_NV04(ctx->push, NV30_3D(VB_ELEMENT_U32), 1);
142 PUSH_DATA (ctx->push, ctx->restart_index);
143 count--;
144 elts++;
145 }
146 }
147 }
148
149 static void
150 emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count)
151 {
152 uint32_t *elts = (uint32_t *)ctx->idxbuf + start;
153
154 while (count) {
155 unsigned push = MIN2(count, ctx->packet_vertex_limit);
156 unsigned size, nr;
157
158 nr = push;
159 if (ctx->primitive_restart)
160 nr = prim_restart_search_i32(elts, push, ctx->restart_index);
161
162 size = ctx->vertex_words * nr;
163
164 BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size);
165
166 ctx->translate->run_elts(ctx->translate, elts, nr, 0, 0, ctx->push->cur);
167
168 ctx->push->cur += size;
169 count -= nr;
170 elts += nr;
171
172 if (nr != push) {
173 BEGIN_NV04(ctx->push, NV30_3D(VB_ELEMENT_U32), 1);
174 PUSH_DATA (ctx->push, ctx->restart_index);
175 count--;
176 elts++;
177 }
178 }
179 }
180
181 static void
182 emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count)
183 {
184 while (count) {
185 unsigned push = MIN2(count, ctx->packet_vertex_limit);
186 unsigned size = ctx->vertex_words * push;
187
188 BEGIN_NI04(ctx->push, NV30_3D(VERTEX_DATA), size);
189
190 ctx->translate->run(ctx->translate, start, push, 0, 0, ctx->push->cur);
191 ctx->push->cur += size;
192 count -= push;
193 start += push;
194 }
195 }
196
197 void
198 nv30_push_vbo(struct nv30_context *nv30, const struct pipe_draw_info *info)
199 {
200 struct push_context ctx;
201 unsigned i, index_size;
202 bool apply_bias = info->index_size && info->index_bias;
203
204 ctx.push = nv30->base.pushbuf;
205 ctx.translate = nv30->vertex->translate;
206 ctx.packet_vertex_limit = nv30->vertex->vtx_per_packet_max;
207 ctx.vertex_words = nv30->vertex->vtx_size;
208
209 for (i = 0; i < nv30->num_vtxbufs; ++i) {
210 uint8_t *data;
211 struct pipe_vertex_buffer *vb = &nv30->vtxbuf[i];
212 struct nv04_resource *res = nv04_resource(vb->buffer.resource);
213
214 if (!vb->buffer.resource) {
215 continue;
216 }
217
218 data = nouveau_resource_map_offset(&nv30->base, res,
219 vb->buffer_offset, NOUVEAU_BO_RD);
220
221 if (apply_bias)
222 data += info->index_bias * vb->stride;
223
224 ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
225 }
226
227 if (info->index_size) {
228 if (!info->has_user_indices)
229 ctx.idxbuf = nouveau_resource_map_offset(&nv30->base,
230 nv04_resource(info->index.resource), info->start * info->index_size,
231 NOUVEAU_BO_RD);
232 else
233 ctx.idxbuf = info->index.user;
234 if (!ctx.idxbuf) {
235 nv30_state_release(nv30);
236 return;
237 }
238 index_size = info->index_size;
239 ctx.primitive_restart = info->primitive_restart;
240 ctx.restart_index = info->restart_index;
241 } else {
242 ctx.idxbuf = NULL;
243 index_size = 0;
244 ctx.primitive_restart = false;
245 ctx.restart_index = 0;
246 }
247
248 if (nv30->screen->eng3d->oclass >= NV40_3D_CLASS) {
249 BEGIN_NV04(ctx.push, NV40_3D(PRIM_RESTART_ENABLE), 2);
250 PUSH_DATA (ctx.push, info->primitive_restart);
251 PUSH_DATA (ctx.push, info->restart_index);
252 nv30->state.prim_restart = info->primitive_restart;
253 }
254
255 ctx.prim = nv30_prim_gl(info->mode);
256
257 PUSH_RESET(ctx.push, BUFCTX_IDXBUF);
258 BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1);
259 PUSH_DATA (ctx.push, ctx.prim);
260 switch (index_size) {
261 case 0:
262 emit_vertices_seq(&ctx, info->start, info->count);
263 break;
264 case 1:
265 emit_vertices_i08(&ctx, info->start, info->count);
266 break;
267 case 2:
268 emit_vertices_i16(&ctx, info->start, info->count);
269 break;
270 case 4:
271 emit_vertices_i32(&ctx, info->start, info->count);
272 break;
273 default:
274 assert(0);
275 break;
276 }
277 BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1);
278 PUSH_DATA (ctx.push, NV30_3D_VERTEX_BEGIN_END_STOP);
279
280 if (info->index_size && !info->has_user_indices)
281 nouveau_resource_unmap(nv04_resource(info->index.resource));
282
283 for (i = 0; i < nv30->num_vtxbufs; ++i) {
284 if (nv30->vtxbuf[i].buffer.resource) {
285 nouveau_resource_unmap(nv04_resource(nv30->vtxbuf[i].buffer.resource));
286 }
287 }
288
289 nv30_state_release(nv30);
290 }