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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * 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/u_format.h"
30 #include "translate/translate.h"
31
32 #include "nouveau/nv_object.xml.h"
33 #include "nv30-40_3d.xml.h"
34 #include "nv30_context.h"
35 #include "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 boolean primitive_restart;
51 uint32_t prim;
52 uint32_t restart_index;
53 };
54
55 static INLINE unsigned
prim_restart_search_i08(uint8_t * elts,unsigned push,uint8_t index)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
prim_restart_search_i16(uint16_t * elts,unsigned push,uint16_t index)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
prim_restart_search_i32(uint32_t * elts,unsigned push,uint32_t index)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
emit_vertices_i08(struct push_context * ctx,unsigned start,unsigned count)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, 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
emit_vertices_i16(struct push_context * ctx,unsigned start,unsigned count)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, 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
emit_vertices_i32(struct push_context * ctx,unsigned start,unsigned count)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, 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
emit_vertices_seq(struct push_context * ctx,unsigned start,unsigned count)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, ctx->push->cur);
191 ctx->push->cur += size;
192 count -= push;
193 start += push;
194 }
195 }
196
197 void
nv30_push_vbo(struct nv30_context * nv30,const struct pipe_draw_info * info)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 boolean apply_bias = info->indexed && 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);
213
214 data = nouveau_resource_map_offset(&nv30->base, res,
215 vb->buffer_offset, NOUVEAU_BO_RD);
216
217 if (apply_bias)
218 data += info->index_bias * vb->stride;
219
220 ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
221 }
222
223 if (info->indexed) {
224 if (nv30->idxbuf.buffer)
225 ctx.idxbuf = nouveau_resource_map_offset(&nv30->base,
226 nv04_resource(nv30->idxbuf.buffer), nv30->idxbuf.offset,
227 NOUVEAU_BO_RD);
228 else
229 ctx.idxbuf = nv30->idxbuf.user_buffer;
230 if (!ctx.idxbuf) {
231 nv30_state_release(nv30);
232 return;
233 }
234 index_size = nv30->idxbuf.index_size;
235 ctx.primitive_restart = info->primitive_restart;
236 ctx.restart_index = info->restart_index;
237 } else {
238 ctx.idxbuf = NULL;
239 index_size = 0;
240 ctx.primitive_restart = FALSE;
241 ctx.restart_index = 0;
242 }
243
244 if (nv30->screen->eng3d->oclass >= NV40_3D_CLASS) {
245 BEGIN_NV04(ctx.push, NV40_3D(PRIM_RESTART_ENABLE), 2);
246 PUSH_DATA (ctx.push, info->primitive_restart);
247 PUSH_DATA (ctx.push, info->restart_index);
248 nv30->state.prim_restart = info->primitive_restart;
249 }
250
251 ctx.prim = nv30_prim_gl(info->mode);
252
253 PUSH_RESET(ctx.push, BUFCTX_IDXBUF);
254 BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1);
255 PUSH_DATA (ctx.push, ctx.prim);
256 switch (index_size) {
257 case 0:
258 emit_vertices_seq(&ctx, info->start, info->count);
259 break;
260 case 1:
261 emit_vertices_i08(&ctx, info->start, info->count);
262 break;
263 case 2:
264 emit_vertices_i16(&ctx, info->start, info->count);
265 break;
266 case 4:
267 emit_vertices_i32(&ctx, info->start, info->count);
268 break;
269 default:
270 assert(0);
271 break;
272 }
273 BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1);
274 PUSH_DATA (ctx.push, NV30_3D_VERTEX_BEGIN_END_STOP);
275
276 if (info->indexed)
277 nouveau_resource_unmap(nv04_resource(nv30->idxbuf.buffer));
278
279 for (i = 0; i < nv30->num_vtxbufs; ++i)
280 nouveau_resource_unmap(nv04_resource(nv30->vtxbuf[i].buffer));
281
282 nv30_state_release(nv30);
283 }
284