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