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
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, 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, 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, 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, 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,const struct pipe_draw_start_count_bias * draw)198 nv30_push_vbo(struct nv30_context *nv30, const struct pipe_draw_info *info,
199 const struct pipe_draw_start_count_bias *draw)
200 {
201 struct push_context ctx;
202 unsigned i, index_size;
203 bool apply_bias = info->index_size && draw->index_bias;
204
205 ctx.push = nv30->base.pushbuf;
206 ctx.translate = nv30->vertex->translate;
207 ctx.packet_vertex_limit = nv30->vertex->vtx_per_packet_max;
208 ctx.vertex_words = nv30->vertex->vtx_size;
209
210 for (i = 0; i < nv30->num_vtxbufs; ++i) {
211 uint8_t *data;
212 struct pipe_vertex_buffer *vb = &nv30->vtxbuf[i];
213 struct nv04_resource *res = nv04_resource(vb->buffer.resource);
214
215 if (!vb->buffer.resource) {
216 continue;
217 }
218
219 data = nouveau_resource_map_offset(&nv30->base, res,
220 vb->buffer_offset, NOUVEAU_BO_RD);
221
222 if (apply_bias)
223 data += draw->index_bias * vb->stride;
224
225 ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
226 }
227
228 if (info->index_size) {
229 if (!info->has_user_indices)
230 ctx.idxbuf = nouveau_resource_map_offset(&nv30->base,
231 nv04_resource(info->index.resource), draw->start * info->index_size,
232 NOUVEAU_BO_RD);
233 else
234 ctx.idxbuf = (char*)info->index.user + draw->start * info->index_size;
235 if (!ctx.idxbuf) {
236 nv30_state_release(nv30);
237 return;
238 }
239 index_size = info->index_size;
240 ctx.primitive_restart = info->primitive_restart;
241 ctx.restart_index = info->restart_index;
242 } else {
243 ctx.idxbuf = NULL;
244 index_size = 0;
245 ctx.primitive_restart = false;
246 ctx.restart_index = 0;
247 }
248
249 if (nv30->screen->eng3d->oclass >= NV40_3D_CLASS) {
250 BEGIN_NV04(ctx.push, NV40_3D(PRIM_RESTART_ENABLE), 2);
251 PUSH_DATA (ctx.push, info->primitive_restart);
252 PUSH_DATA (ctx.push, info->restart_index);
253 nv30->state.prim_restart = info->primitive_restart;
254 }
255
256 ctx.prim = nv30_prim_gl(info->mode);
257
258 PUSH_RESET(ctx.push, BUFCTX_IDXBUF);
259 BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1);
260 PUSH_DATA (ctx.push, ctx.prim);
261 switch (index_size) {
262 case 0:
263 emit_vertices_seq(&ctx, draw->start, draw->count);
264 break;
265 case 1:
266 emit_vertices_i08(&ctx, draw->start, draw->count);
267 break;
268 case 2:
269 emit_vertices_i16(&ctx, draw->start, draw->count);
270 break;
271 case 4:
272 emit_vertices_i32(&ctx, draw->start, draw->count);
273 break;
274 default:
275 assert(0);
276 break;
277 }
278 BEGIN_NV04(ctx.push, NV30_3D(VERTEX_BEGIN_END), 1);
279 PUSH_DATA (ctx.push, NV30_3D_VERTEX_BEGIN_END_STOP);
280
281 if (info->index_size && !info->has_user_indices)
282 nouveau_resource_unmap(nv04_resource(info->index.resource));
283
284 for (i = 0; i < nv30->num_vtxbufs; ++i) {
285 if (nv30->vtxbuf[i].buffer.resource) {
286 nouveau_resource_unmap(nv04_resource(nv30->vtxbuf[i].buffer.resource));
287 }
288 }
289
290 nv30_state_release(nv30);
291 }
292