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 "draw/draw_context.h"
27 #include "draw/draw_vertex.h"
28 #include "draw/draw_pipe.h"
29 #include "draw/draw_vbuf.h"
30 #include "draw/draw_private.h"
31 
32 #include "nouveau/nv_object.xml.h"
33 #include "nv30-40_3d.xml.h"
34 #include "nv30_context.h"
35 #include "nv30_format.h"
36 
37 struct nv30_render {
38    struct vbuf_render base;
39    struct nv30_context *nv30;
40 
41    struct pipe_transfer *transfer;
42    struct pipe_resource *buffer;
43    unsigned offset;
44    unsigned length;
45 
46    struct vertex_info vertex_info;
47 
48    struct nouveau_heap *vertprog;
49    uint32_t vtxprog[16][4];
50    uint32_t vtxfmt[16];
51    uint32_t vtxptr[16];
52    uint32_t prim;
53 };
54 
55 static INLINE struct nv30_render *
nv30_render(struct vbuf_render * render)56 nv30_render(struct vbuf_render *render)
57 {
58    return (struct nv30_render *)render;
59 }
60 
61 static const struct vertex_info *
nv30_render_get_vertex_info(struct vbuf_render * render)62 nv30_render_get_vertex_info(struct vbuf_render *render)
63 {
64    return &nv30_render(render)->vertex_info;
65 }
66 
67 static boolean
nv30_render_allocate_vertices(struct vbuf_render * render,ushort vertex_size,ushort nr_vertices)68 nv30_render_allocate_vertices(struct vbuf_render *render,
69                               ushort vertex_size, ushort nr_vertices)
70 {
71    struct nv30_render *r = nv30_render(render);
72    struct nv30_context *nv30 = r->nv30;
73 
74    r->length = vertex_size * nr_vertices;
75 
76    if (r->offset + r->length >= render->max_vertex_buffer_bytes) {
77       pipe_resource_reference(&r->buffer, NULL);
78       r->buffer = pipe_buffer_create(&nv30->screen->base.base,
79                                      PIPE_BIND_VERTEX_BUFFER, 0,
80                                      render->max_vertex_buffer_bytes);
81       if (!r->buffer)
82          return FALSE;
83 
84       r->offset = 0;
85    }
86 
87    return TRUE;
88 }
89 
90 static void *
nv30_render_map_vertices(struct vbuf_render * render)91 nv30_render_map_vertices(struct vbuf_render *render)
92 {
93    struct nv30_render *r = nv30_render(render);
94    char *map = pipe_buffer_map(&r->nv30->base.pipe, r->buffer,
95                                PIPE_TRANSFER_WRITE |
96                                PIPE_TRANSFER_UNSYNCHRONIZED, &r->transfer);
97    return map + r->offset;
98 }
99 
100 static void
nv30_render_unmap_vertices(struct vbuf_render * render,ushort min_index,ushort max_index)101 nv30_render_unmap_vertices(struct vbuf_render *render,
102                            ushort min_index, ushort max_index)
103 {
104    struct nv30_render *r = nv30_render(render);
105    pipe_buffer_unmap(&r->nv30->base.pipe, r->transfer);
106 }
107 
108 static void
nv30_render_set_primitive(struct vbuf_render * render,unsigned prim)109 nv30_render_set_primitive(struct vbuf_render *render, unsigned prim)
110 {
111    struct nv30_render *r = nv30_render(render);
112 
113    r->prim = nv30_prim_gl(prim);
114 }
115 
116 static void
nv30_render_draw_elements(struct vbuf_render * render,const ushort * indices,uint count)117 nv30_render_draw_elements(struct vbuf_render *render,
118                           const ushort *indices, uint count)
119 {
120    struct nv30_render *r = nv30_render(render);
121    struct nv30_context *nv30 = r->nv30;
122    struct nouveau_pushbuf *push = nv30->screen->base.pushbuf;
123    unsigned i;
124 
125    BEGIN_NV04(push, NV30_3D(VTXBUF(0)), r->vertex_info.num_attribs);
126    for (i = 0; i < r->vertex_info.num_attribs; i++) {
127       PUSH_RESRC(push, NV30_3D(VTXBUF(i)), BUFCTX_VTXTMP,
128                        nv04_resource(r->buffer), r->offset + r->vtxptr[i],
129                        NOUVEAU_BO_LOW | NOUVEAU_BO_RD, 0, 0);
130    }
131 
132    if (!nv30_state_validate(nv30, FALSE))
133       return;
134 
135    BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
136    PUSH_DATA (push, r->prim);
137 
138    if (count & 1) {
139       BEGIN_NV04(push, NV30_3D(VB_ELEMENT_U32), 1);
140       PUSH_DATA (push, *indices++);
141    }
142 
143    count >>= 1;
144    while (count) {
145       unsigned npush = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN);
146       count -= npush;
147 
148       BEGIN_NI04(push, NV30_3D(VB_ELEMENT_U16), npush);
149       while (npush--) {
150          PUSH_DATA(push, (indices[1] << 16) | indices[0]);
151          indices += 2;
152       }
153    }
154 
155    BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
156    PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP);
157    PUSH_RESET(push, BUFCTX_VTXTMP);
158 }
159 
160 static void
nv30_render_draw_arrays(struct vbuf_render * render,unsigned start,uint nr)161 nv30_render_draw_arrays(struct vbuf_render *render, unsigned start, uint nr)
162 {
163    struct nv30_render *r = nv30_render(render);
164    struct nv30_context *nv30 = r->nv30;
165    struct nouveau_pushbuf *push = nv30->base.pushbuf;
166    unsigned fn = nr >> 8, pn = nr & 0xff;
167    unsigned ps = fn + (pn ? 1 : 0);
168    unsigned i;
169 
170    BEGIN_NV04(push, NV30_3D(VTXBUF(0)), r->vertex_info.num_attribs);
171    for (i = 0; i < r->vertex_info.num_attribs; i++) {
172       PUSH_RESRC(push, NV30_3D(VTXBUF(i)), BUFCTX_VTXTMP,
173                        nv04_resource(r->buffer), r->offset + r->vtxptr[i],
174                        NOUVEAU_BO_LOW | NOUVEAU_BO_RD, 0, 0);
175    }
176 
177    if (!nv30_state_validate(nv30, FALSE))
178       return;
179 
180    BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
181    PUSH_DATA (push, r->prim);
182 
183    BEGIN_NI04(push, NV30_3D(VB_VERTEX_BATCH), ps);
184    while (fn--) {
185       PUSH_DATA (push, 0xff000000 | start);
186       start += 256;
187    }
188 
189    if (pn)
190       PUSH_DATA (push, ((pn - 1) << 24) | start);
191 
192    BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
193    PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP);
194    PUSH_RESET(push, BUFCTX_VTXTMP);
195 }
196 
197 static void
nv30_render_release_vertices(struct vbuf_render * render)198 nv30_render_release_vertices(struct vbuf_render *render)
199 {
200    struct nv30_render *r = nv30_render(render);
201    r->offset += r->length;
202 }
203 
204 static const struct {
205    unsigned emit;
206    unsigned interp;
207    unsigned vp30;
208    unsigned vp40;
209    unsigned ow40;
210 } vroute [] = {
211    [TGSI_SEMANTIC_POSITION] = { EMIT_4F, INTERP_PERSPECTIVE, 0, 0, 0x00000000 },
212    [TGSI_SEMANTIC_COLOR   ] = { EMIT_4F, INTERP_LINEAR     , 3, 1, 0x00000001 },
213    [TGSI_SEMANTIC_BCOLOR  ] = { EMIT_4F, INTERP_LINEAR     , 1, 3, 0x00000004 },
214    [TGSI_SEMANTIC_FOG     ] = { EMIT_4F, INTERP_PERSPECTIVE, 5, 5, 0x00000010 },
215    [TGSI_SEMANTIC_PSIZE   ] = { EMIT_1F_PSIZE, INTERP_POS  , 6, 6, 0x00000020 },
216    [TGSI_SEMANTIC_GENERIC ] = { EMIT_4F, INTERP_PERSPECTIVE, 8, 7, 0x00004000 }
217 };
218 
219 static boolean
vroute_add(struct nv30_render * r,uint attrib,uint sem,uint * idx)220 vroute_add(struct nv30_render *r, uint attrib, uint sem, uint *idx)
221 {
222    struct pipe_screen *pscreen = &r->nv30->screen->base.base;
223    struct nv30_fragprog *fp = r->nv30->fragprog.program;
224    struct vertex_info *vinfo = &r->vertex_info;
225    enum pipe_format format;
226    uint emit = EMIT_OMIT;
227    uint result = *idx;
228 
229    if (sem == TGSI_SEMANTIC_GENERIC && result >= 8) {
230       for (result = 0; result < 8; result++) {
231          if (fp->texcoord[result] == *idx) {
232             emit = vroute[sem].emit;
233             break;
234          }
235       }
236    } else {
237       emit = vroute[sem].emit;
238    }
239 
240    if (emit == EMIT_OMIT)
241       return FALSE;
242 
243    draw_emit_vertex_attr(vinfo, emit, vroute[sem].interp, attrib);
244    format = draw_translate_vinfo_format(emit);
245 
246    r->vtxfmt[attrib] = nv30_vtxfmt(pscreen, format)->hw;
247    r->vtxptr[attrib] = vinfo->size | NV30_3D_VTXBUF_DMA1;
248    vinfo->size += draw_translate_vinfo_size(emit);
249 
250    if (nv30_screen(pscreen)->eng3d->oclass < NV40_3D_CLASS) {
251       r->vtxprog[attrib][0] = 0x001f38d8;
252       r->vtxprog[attrib][1] = 0x0080001b | (attrib << 9);
253       r->vtxprog[attrib][2] = 0x0836106c;
254       r->vtxprog[attrib][3] = 0x2000f800 | (result + vroute[sem].vp30) << 2;
255    } else {
256       r->vtxprog[attrib][0] = 0x401f9c6c;
257       r->vtxprog[attrib][1] = 0x0040000d | (attrib << 8);
258       r->vtxprog[attrib][2] = 0x8106c083;
259       r->vtxprog[attrib][3] = 0x6041ff80 | (result + vroute[sem].vp40) << 2;
260    }
261 
262    *idx = vroute[sem].ow40 << result;
263    return TRUE;
264 }
265 
266 static boolean
nv30_render_validate(struct nv30_context * nv30)267 nv30_render_validate(struct nv30_context *nv30)
268 {
269    struct nv30_render *r = nv30_render(nv30->draw->render);
270    struct nv30_rasterizer_stateobj *rast = nv30->rast;
271    struct pipe_screen *pscreen = &nv30->screen->base.base;
272    struct nouveau_pushbuf *push = nv30->screen->base.pushbuf;
273    struct nouveau_object *eng3d = nv30->screen->eng3d;
274    struct nv30_vertprog *vp = nv30->vertprog.program;
275    struct vertex_info *vinfo = &r->vertex_info;
276    unsigned vp_attribs = 0;
277    unsigned vp_results = 0;
278    unsigned attrib = 0;
279    unsigned pntc;
280    int i;
281 
282    if (!r->vertprog) {
283       struct nouveau_heap *heap = nv30_screen(pscreen)->vp_exec_heap;
284       if (nouveau_heap_alloc(heap, 16, &r->vertprog, &r->vertprog)) {
285          while (heap->next && heap->size < 16) {
286             struct nouveau_heap **evict = heap->next->priv;
287             nouveau_heap_free(evict);
288          }
289 
290          if (nouveau_heap_alloc(heap, 16, &r->vertprog, &r->vertprog))
291             return FALSE;
292       }
293    }
294 
295    vinfo->num_attribs = 0;
296    vinfo->size = 0;
297 
298    /* setup routing for all necessary vp outputs */
299    for (i = 0; i < vp->info.num_outputs && attrib < 16; i++) {
300       uint semantic = vp->info.output_semantic_name[i];
301       uint index = vp->info.output_semantic_index[i];
302       if (vroute_add(r, attrib, semantic, &index)) {
303          vp_attribs |= (1 << attrib++);
304          vp_results |= index;
305       }
306    }
307 
308    /* setup routing for replaced point coords not written by vp */
309    if (rast && rast->pipe.point_quad_rasterization)
310       pntc = rast->pipe.sprite_coord_enable & 0x000002ff;
311    else
312       pntc = 0;
313 
314    while (pntc && attrib < 16) {
315       uint index = ffs(pntc) - 1; pntc &= ~(1 << index);
316       if (vroute_add(r, attrib, TGSI_SEMANTIC_GENERIC, &index)) {
317          vp_attribs |= (1 << attrib++);
318          vp_results |= index;
319       }
320    }
321 
322    /* modify vertex format for correct stride, and stub out unused ones */
323    BEGIN_NV04(push, NV30_3D(VP_UPLOAD_FROM_ID), 1);
324    PUSH_DATA (push, r->vertprog->start);
325    r->vtxprog[attrib - 1][3] |= 1;
326    for (i = 0; i < attrib; i++) {
327       BEGIN_NV04(push, NV30_3D(VP_UPLOAD_INST(0)), 4);
328       PUSH_DATAp(push, r->vtxprog[i], 4);
329       r->vtxfmt[i] |= vinfo->size << 8;
330    }
331    for (; i < 16; i++)
332       r->vtxfmt[i]  = NV30_3D_VTXFMT_TYPE_V32_FLOAT;
333 
334    BEGIN_NV04(push, NV30_3D(VIEWPORT_TRANSLATE_X), 8);
335    PUSH_DATAf(push, 0.0);
336    PUSH_DATAf(push, 0.0);
337    PUSH_DATAf(push, 0.0);
338    PUSH_DATAf(push, 0.0);
339    PUSH_DATAf(push, 1.0);
340    PUSH_DATAf(push, 1.0);
341    PUSH_DATAf(push, 1.0);
342    PUSH_DATAf(push, 1.0);
343    BEGIN_NV04(push, NV30_3D(DEPTH_RANGE_NEAR), 2);
344    PUSH_DATAf(push, 0.0);
345    PUSH_DATAf(push, 1.0);
346 
347    BEGIN_NV04(push, NV30_3D(VTXFMT(0)), 16);
348    PUSH_DATAp(push, r->vtxfmt, 16);
349 
350    BEGIN_NV04(push, NV30_3D(VP_START_FROM_ID), 1);
351    PUSH_DATA (push, r->vertprog->start);
352    BEGIN_NV04(push, NV30_3D(ENGINE), 1);
353    PUSH_DATA (push, 0x00000103);
354    if (eng3d->oclass >= NV40_3D_CLASS) {
355       BEGIN_NV04(push, NV40_3D(VP_ATTRIB_EN), 2);
356       PUSH_DATA (push, vp_attribs);
357       PUSH_DATA (push, vp_results);
358    }
359 
360    vinfo->size /= 4;
361    return TRUE;
362 }
363 
364 void
nv30_render_vbo(struct pipe_context * pipe,const struct pipe_draw_info * info)365 nv30_render_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
366 {
367    struct nv30_context *nv30 = nv30_context(pipe);
368    struct draw_context *draw = nv30->draw;
369    struct pipe_transfer *transfer[PIPE_MAX_ATTRIBS] = {NULL};
370    struct pipe_transfer *transferi = NULL;
371    int i;
372 
373    nv30_render_validate(nv30);
374 
375    if (nv30->draw_dirty & NV30_NEW_VIEWPORT)
376       draw_set_viewport_state(draw, &nv30->viewport);
377    if (nv30->draw_dirty & NV30_NEW_RASTERIZER)
378       draw_set_rasterizer_state(draw, &nv30->rast->pipe, NULL);
379    if (nv30->draw_dirty & NV30_NEW_CLIP)
380       draw_set_clip_state(draw, &nv30->clip);
381    if (nv30->draw_dirty & NV30_NEW_ARRAYS) {
382       draw_set_vertex_buffers(draw, nv30->num_vtxbufs, nv30->vtxbuf);
383       draw_set_vertex_elements(draw, nv30->vertex->num_elements, nv30->vertex->pipe);
384    }
385    if (nv30->draw_dirty & NV30_NEW_FRAGPROG) {
386       struct nv30_fragprog *fp = nv30->fragprog.program;
387       if (!fp->draw)
388          fp->draw = draw_create_fragment_shader(draw, &fp->pipe);
389       draw_bind_fragment_shader(draw, fp->draw);
390    }
391    if (nv30->draw_dirty & NV30_NEW_VERTPROG) {
392       struct nv30_vertprog *vp = nv30->vertprog.program;
393       if (!vp->draw)
394          vp->draw = draw_create_vertex_shader(draw, &vp->pipe);
395       draw_bind_vertex_shader(draw, vp->draw);
396    }
397    if (nv30->draw_dirty & NV30_NEW_VERTCONST) {
398       if (nv30->vertprog.constbuf) {
399          void *map = nv04_resource(nv30->vertprog.constbuf)->data;
400          draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0,
401                                          map, nv30->vertprog.constbuf_nr);
402       }
403    }
404 
405    for (i = 0; i < nv30->num_vtxbufs; i++) {
406       const void *map = nv30->vtxbuf[i].user_buffer;
407       if (!map)
408          map = pipe_buffer_map(pipe, nv30->vtxbuf[i].buffer,
409                                   PIPE_TRANSFER_UNSYNCHRONIZED |
410                                   PIPE_TRANSFER_READ, &transfer[i]);
411       draw_set_mapped_vertex_buffer(draw, i, map);
412    }
413 
414    if (info->indexed) {
415       const void *map = nv30->idxbuf.user_buffer;
416       if (!map)
417          pipe_buffer_map(pipe, nv30->idxbuf.buffer,
418                                   PIPE_TRANSFER_UNSYNCHRONIZED |
419                                   PIPE_TRANSFER_READ, &transferi);
420       draw_set_indexes(draw,
421                        (ubyte *) map + nv30->idxbuf.offset,
422                        nv30->idxbuf.index_size);
423    } else {
424       draw_set_indexes(draw, NULL, 0);
425    }
426 
427    draw_vbo(draw, info);
428    draw_flush(draw);
429 
430    if (info->indexed && transferi)
431       pipe_buffer_unmap(pipe, transferi);
432    for (i = 0; i < nv30->num_vtxbufs; i++)
433       if (transfer[i])
434          pipe_buffer_unmap(pipe, transfer[i]);
435 
436    nv30->draw_dirty = 0;
437    nv30_state_release(nv30);
438 }
439 
440 static void
nv30_render_destroy(struct vbuf_render * render)441 nv30_render_destroy(struct vbuf_render *render)
442 {
443    FREE(render);
444 }
445 
446 static struct vbuf_render *
nv30_render_create(struct nv30_context * nv30)447 nv30_render_create(struct nv30_context *nv30)
448 {
449    struct nv30_render *r = CALLOC_STRUCT(nv30_render);
450    if (!r)
451       return NULL;
452 
453    r->nv30 = nv30;
454    r->offset = 1 * 1024 * 1024;
455 
456    r->base.max_indices = 16 * 1024;
457    r->base.max_vertex_buffer_bytes = r->offset;
458 
459    r->base.get_vertex_info = nv30_render_get_vertex_info;
460    r->base.allocate_vertices = nv30_render_allocate_vertices;
461    r->base.map_vertices = nv30_render_map_vertices;
462    r->base.unmap_vertices = nv30_render_unmap_vertices;
463    r->base.set_primitive = nv30_render_set_primitive;
464    r->base.draw_elements = nv30_render_draw_elements;
465    r->base.draw_arrays = nv30_render_draw_arrays;
466    r->base.release_vertices = nv30_render_release_vertices;
467    r->base.destroy = nv30_render_destroy;
468    return &r->base;
469 }
470 
471 void
nv30_draw_init(struct pipe_context * pipe)472 nv30_draw_init(struct pipe_context *pipe)
473 {
474    struct nv30_context *nv30 = nv30_context(pipe);
475    struct vbuf_render *render;
476    struct draw_context *draw;
477    struct draw_stage *stage;
478 
479    draw = draw_create(pipe);
480    if (!draw)
481       return;
482 
483    render = nv30_render_create(nv30);
484    if (!render) {
485       draw_destroy(draw);
486       return;
487    }
488 
489    stage = draw_vbuf_stage(draw, render);
490    if (!stage) {
491       render->destroy(render);
492       draw_destroy(draw);
493       return;
494    }
495 
496    draw_set_render(draw, render);
497    draw_set_rasterize_stage(draw, stage);
498    draw_wide_line_threshold(draw, 10000000.f);
499    draw_wide_point_threshold(draw, 10000000.f);
500    draw_wide_point_sprites(draw, TRUE);
501    nv30->draw = draw;
502 }
503