Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / drivers / nv50 / nv50_shader_state.c
1 /*
2  * Copyright 2008 Ben Skeggs
3  * Copyright 2010 Christoph Bumiller
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
20  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23
24 #include "pipe/p_context.h"
25 #include "pipe/p_defines.h"
26 #include "pipe/p_state.h"
27 #include "util/u_inlines.h"
28
29 #include "nv50_context.h"
30
31 void
32 nv50_constbufs_validate(struct nv50_context *nv50)
33 {
34    struct nouveau_channel *chan = nv50->screen->base.channel;
35    unsigned s;
36
37    for (s = 0; s < 3; ++s) {
38       struct nv04_resource *res;
39       int i;
40       unsigned p, b;
41
42       if (s == PIPE_SHADER_FRAGMENT)
43          p = NV50_3D_SET_PROGRAM_CB_PROGRAM_FRAGMENT;
44       else
45       if (s == PIPE_SHADER_GEOMETRY)
46          p = NV50_3D_SET_PROGRAM_CB_PROGRAM_GEOMETRY;
47       else
48          p = NV50_3D_SET_PROGRAM_CB_PROGRAM_VERTEX;
49
50       while (nv50->constbuf_dirty[s]) {
51          struct nouveau_bo *bo;
52          unsigned start = 0;
53          unsigned words = 0;
54
55          i = ffs(nv50->constbuf_dirty[s]) - 1;
56          nv50->constbuf_dirty[s] &= ~(1 << i);
57
58          res = nv04_resource(nv50->constbuf[s][i]);
59          if (!res) {
60             if (i != 0) {
61                BEGIN_RING(chan, RING_3D(SET_PROGRAM_CB), 1);
62                OUT_RING  (chan, (i << 8) | p | 0);
63             }
64             continue;
65          }
66
67          if (i == 0) {
68             b = NV50_CB_PVP + s;
69
70             /* always upload GL uniforms through CB DATA */
71             bo = nv50->screen->uniforms;
72             words = res->base.width0 / 4;
73          } else {
74             b = s * 16 + i;
75
76             assert(0);
77
78             if (!nouveau_resource_mapped_by_gpu(&res->base)) {
79                nouveau_buffer_migrate(&nv50->base, res, NOUVEAU_BO_VRAM);
80
81                BEGIN_RING(chan, RING_3D(CODE_CB_FLUSH), 1);
82                OUT_RING  (chan, 0);
83             }
84             MARK_RING (chan, 6, 2);
85             BEGIN_RING(chan, RING_3D(CB_DEF_ADDRESS_HIGH), 3);
86             OUT_RESRCh(chan, res, 0, NOUVEAU_BO_RD);
87             OUT_RESRCl(chan, res, 0, NOUVEAU_BO_RD);
88             OUT_RING  (chan, (b << 16) | (res->base.width0 & 0xffff));
89             BEGIN_RING(chan, RING_3D(SET_PROGRAM_CB), 1);
90             OUT_RING  (chan, (b << 12) | (i << 8) | p | 1);
91
92             bo = res->bo;
93
94             nv50_bufctx_add_resident(nv50, NV50_BUFCTX_CONSTANT, res,
95                                      res->domain | NOUVEAU_BO_RD);
96          }
97
98          if (words) {
99             MARK_RING(chan, 8, 1);
100
101             nouveau_bo_validate(chan, bo, res->domain | NOUVEAU_BO_WR);
102          }
103
104          while (words) {
105             unsigned nr = AVAIL_RING(chan);
106
107             if (nr < 16) {
108                FIRE_RING(chan);
109                nouveau_bo_validate(chan, bo, res->domain | NOUVEAU_BO_WR);
110                continue;
111             }
112             nr = MIN2(MIN2(nr - 3, words), NV04_PFIFO_MAX_PACKET_LEN);
113
114             BEGIN_RING(chan, RING_3D(CB_ADDR), 1);
115             OUT_RING  (chan, (start << 8) | b);
116             BEGIN_RING_NI(chan, RING_3D(CB_DATA(0)), nr);
117             OUT_RINGp (chan, &res->data[start * 4], nr);
118
119             start += nr;
120             words -= nr;
121          }
122       }
123    }
124 }
125
126 static boolean
127 nv50_program_validate(struct nv50_context *nv50, struct nv50_program *prog)
128 {
129    struct nouveau_resource *heap;
130    int ret;
131    unsigned size;
132
133    if (prog->translated)
134       return TRUE;
135
136    prog->translated = nv50_program_translate(prog);
137    if (!prog->translated)
138       return FALSE;
139
140    if (prog->type == PIPE_SHADER_FRAGMENT) heap = nv50->screen->fp_code_heap;
141    else
142    if (prog->type == PIPE_SHADER_GEOMETRY) heap = nv50->screen->gp_code_heap;
143    else
144       heap = nv50->screen->vp_code_heap;
145
146    size = align(prog->code_size, 0x100);
147
148    ret = nouveau_resource_alloc(heap, size, prog, &prog->res);
149    if (ret) {
150       NOUVEAU_ERR("out of code space for shader type %i\n", prog->type);
151       return FALSE;
152    }
153    prog->code_base = prog->res->start;
154
155    nv50_relocate_program(prog, prog->code_base, 0);
156
157    nv50_sifc_linear_u8(&nv50->base, nv50->screen->code,
158                        (prog->type << NV50_CODE_BO_SIZE_LOG2) + prog->code_base,
159                        NOUVEAU_BO_VRAM, prog->code_size, prog->code);
160
161    BEGIN_RING(nv50->screen->base.channel, RING_3D(CODE_CB_FLUSH), 1);
162    OUT_RING  (nv50->screen->base.channel, 0);
163
164    return TRUE;
165 }
166
167 void
168 nv50_vertprog_validate(struct nv50_context *nv50)
169 {
170    struct nouveau_channel *chan = nv50->screen->base.channel;
171    struct nv50_program *vp = nv50->vertprog;
172
173    if (nv50->clip.nr > vp->vp.clpd_nr) {
174       if (vp->translated)
175          nv50_program_destroy(nv50, vp);
176       vp->vp.clpd_nr = nv50->clip.nr;
177    }
178
179    if (!nv50_program_validate(nv50, vp))
180          return;
181
182    BEGIN_RING(chan, RING_3D(VP_ATTR_EN(0)), 2);
183    OUT_RING  (chan, vp->vp.attrs[0]);
184    OUT_RING  (chan, vp->vp.attrs[1]);
185    BEGIN_RING(chan, RING_3D(VP_REG_ALLOC_RESULT), 1);
186    OUT_RING  (chan, vp->max_out);
187    BEGIN_RING(chan, RING_3D(VP_REG_ALLOC_TEMP), 1);
188    OUT_RING  (chan, vp->max_gpr);
189    BEGIN_RING(chan, RING_3D(VP_START_ID), 1);
190    OUT_RING  (chan, vp->code_base);
191 }
192
193 void
194 nv50_fragprog_validate(struct nv50_context *nv50)
195 {
196    struct nouveau_channel *chan = nv50->screen->base.channel;
197    struct nv50_program *fp = nv50->fragprog;
198
199    if (!nv50_program_validate(nv50, fp))
200          return;
201
202    BEGIN_RING(chan, RING_3D(FP_REG_ALLOC_TEMP), 1);
203    OUT_RING  (chan, fp->max_gpr);
204    BEGIN_RING(chan, RING_3D(FP_RESULT_COUNT), 1);
205    OUT_RING  (chan, fp->max_out);
206    BEGIN_RING(chan, RING_3D(FP_CONTROL), 1);
207    OUT_RING  (chan, fp->fp.flags[0]);
208    BEGIN_RING(chan, RING_3D(FP_CTRL_UNK196C), 1);
209    OUT_RING  (chan, fp->fp.flags[1]);
210    BEGIN_RING(chan, RING_3D(FP_START_ID), 1);
211    OUT_RING  (chan, fp->code_base);
212 }
213
214 void
215 nv50_gmtyprog_validate(struct nv50_context *nv50)
216 {
217    struct nouveau_channel *chan = nv50->screen->base.channel;
218    struct nv50_program *gp = nv50->gmtyprog;
219
220    if (!gp) /* GP_ENABLE is updated in linkage validation */
221       return;
222    if (!nv50_program_validate(nv50, gp))
223       return;
224
225    BEGIN_RING(chan, RING_3D(GP_REG_ALLOC_TEMP), 1);
226    OUT_RING  (chan, gp->max_gpr);
227    BEGIN_RING(chan, RING_3D(GP_REG_ALLOC_RESULT), 1);
228    OUT_RING  (chan, gp->max_out);
229    BEGIN_RING(chan, RING_3D(GP_OUTPUT_PRIMITIVE_TYPE), 1);
230    OUT_RING  (chan, gp->gp.prim_type);
231    BEGIN_RING(chan, RING_3D(GP_VERTEX_OUTPUT_COUNT), 1);
232    OUT_RING  (chan, gp->gp.vert_count);
233    BEGIN_RING(chan, RING_3D(GP_START_ID), 1);
234    OUT_RING  (chan, gp->code_base);
235 }
236
237 static void
238 nv50_sprite_coords_validate(struct nv50_context *nv50)
239 {
240    struct nouveau_channel *chan = nv50->screen->base.channel;
241    uint32_t pntc[8], mode;
242    struct nv50_program *fp = nv50->fragprog;
243    unsigned i, c;
244    unsigned m = (nv50->state.interpolant_ctrl >> 8) & 0xff;
245
246    if (!nv50->rast->pipe.point_quad_rasterization) {
247       if (nv50->state.point_sprite) {
248          BEGIN_RING(chan, RING_3D(POINT_COORD_REPLACE_MAP(0)), 8);
249          for (i = 0; i < 8; ++i)
250             OUT_RING(chan, 0);
251
252          nv50->state.point_sprite = FALSE;
253       }
254       return;
255    } else {
256       nv50->state.point_sprite = TRUE;
257    }
258
259    memset(pntc, 0, sizeof(pntc));
260
261    for (i = 0; i < fp->in_nr; i++) {
262       unsigned n = util_bitcount(fp->in[i].mask);
263
264       if (fp->in[i].sn != TGSI_SEMANTIC_GENERIC) {
265          m += n;
266          continue;
267       }
268       if (!(nv50->rast->pipe.sprite_coord_enable & (1 << fp->in[i].si))) {
269          m += n;
270          continue;
271       }
272
273       for (c = 0; c < 4; ++c) {
274          if (fp->in[i].mask & (1 << c)) {
275             pntc[m / 8] |= (c + 1) << ((m % 8) * 4);
276             ++m;
277          }
278       }
279    }
280
281    if (nv50->rast->pipe.sprite_coord_mode == PIPE_SPRITE_COORD_LOWER_LEFT)
282       mode = 0x00;
283    else
284       mode = 0x10;
285
286    BEGIN_RING(chan, RING_3D(POINT_SPRITE_CTRL), 1);
287    OUT_RING  (chan, mode);
288
289    BEGIN_RING(chan, RING_3D(POINT_COORD_REPLACE_MAP(0)), 8);
290    OUT_RINGp (chan, pntc, 8);
291 }
292
293 /* Validate state derived from shaders and the rasterizer cso. */
294 void
295 nv50_validate_derived_rs(struct nv50_context *nv50)
296 {
297    struct nouveau_channel *chan = nv50->screen->base.channel;
298    uint32_t color, psize;
299
300    nv50_sprite_coords_validate(nv50);
301
302    if (nv50->dirty & NV50_NEW_FRAGPROG)
303       return;
304    psize = nv50->state.semantic_psize & ~NV50_3D_MAP_SEMANTIC_3_PTSZ_EN__MASK;
305    color = nv50->state.semantic_color & ~NV50_3D_MAP_SEMANTIC_0_CLMP_EN;
306
307    if (nv50->rast->pipe.clamp_vertex_color)
308       color |= NV50_3D_MAP_SEMANTIC_0_CLMP_EN;
309
310    if (color != nv50->state.semantic_color) {
311       nv50->state.semantic_color = color;
312       BEGIN_RING(chan, RING_3D(MAP_SEMANTIC_0), 1);
313       OUT_RING  (chan, color);
314    }
315
316    if (nv50->rast->pipe.point_size_per_vertex)
317       psize |= NV50_3D_MAP_SEMANTIC_3_PTSZ_EN__MASK;
318
319    if (psize != nv50->state.semantic_psize) {
320       nv50->state.semantic_psize = psize;
321       BEGIN_RING(chan, RING_3D(MAP_SEMANTIC_3), 1);
322       OUT_RING  (chan, psize);
323    }
324 }
325
326 static int
327 nv50_vec4_map(uint8_t *map, int mid, uint32_t lin[4],
328               struct nv50_varying *in, struct nv50_varying *out)
329 {
330    int c;
331    uint8_t mv = out->mask, mf = in->mask, oid = out->hw;
332
333    for (c = 0; c < 4; ++c) {
334       if (mf & 1) {
335          if (in->linear)
336             lin[mid / 32] |= 1 << (mid % 32);
337          if (mv & 1)
338             map[mid] = oid;
339          else
340          if (c == 3)
341             map[mid] |= 1;
342          ++mid;
343       }
344
345       oid += mv & 1;
346       mf >>= 1;
347       mv >>= 1;
348    }
349
350    return mid;
351 }
352
353 void
354 nv50_fp_linkage_validate(struct nv50_context *nv50)
355 {
356    struct nouveau_channel *chan = nv50->screen->base.channel;
357    struct nv50_program *vp = nv50->gmtyprog ? nv50->gmtyprog : nv50->vertprog;
358    struct nv50_program *fp = nv50->fragprog;
359    struct nv50_varying dummy;
360    int i, n, c, m;
361    uint32_t primid = 0;
362    uint32_t psiz = 0x000;
363    uint32_t interp = fp->fp.interp;
364    uint32_t colors = fp->fp.colors;
365    uint32_t lin[4];
366    uint8_t map[64];
367
368    memset(lin, 0x00, sizeof(lin));
369
370    /* XXX: in buggy-endian mode, is the first element of map (u32)0x000000xx
371     *  or is it the first byte ?
372     */
373    memset(map, nv50->gmtyprog ? 0x80 : 0x40, sizeof(map));
374
375    dummy.mask = 0xf; /* map all components of HPOS */
376    dummy.linear = 0;
377    m = nv50_vec4_map(map, 0, lin, &dummy, &vp->out[0]);
378
379    for (c = 0; c < vp->vp.clpd_nr; ++c)
380       map[m++] = vp->vp.clpd + c;
381
382    colors |= m << 8; /* adjust BFC0 id */
383
384    /* if light_twoside is active, FFC0_ID == BFC0_ID is invalid */
385    if (nv50->rast->pipe.light_twoside) {
386       for (i = 0; i < 2; ++i)
387          m = nv50_vec4_map(map, m, lin,
388                            &fp->in[fp->vp.bfc[i]], &vp->out[vp->vp.bfc[i]]);
389    }
390    colors += m - 4; /* adjust FFC0 id */
391    interp |= m << 8; /* set map id where 'normal' FP inputs start */
392
393    dummy.mask = 0x0;
394    for (i = 0; i < fp->in_nr; ++i) {
395       for (n = 0; n < vp->out_nr; ++n)
396          if (vp->out[n].sn == fp->in[i].sn &&
397              vp->out[n].si == fp->in[i].si)
398             break;
399       m = nv50_vec4_map(map, m, lin,
400                         &fp->in[i], (n < vp->out_nr) ? &vp->out[n] : &dummy);
401    }
402
403    /* PrimitiveID either is replaced by the system value, or
404     * written by the geometry shader into an output register
405     */
406    if (fp->gp.primid < 0x40) {
407       primid = m;
408       map[m++] = vp->gp.primid;
409    }
410
411    if (nv50->rast->pipe.point_size_per_vertex) {
412       psiz = (m << 4) | 1;
413       map[m++] = vp->vp.psiz;
414    }
415
416    if (nv50->rast->pipe.clamp_vertex_color)
417       colors |= NV50_3D_MAP_SEMANTIC_0_CLMP_EN;
418
419    n = (m + 3) / 4;
420    assert(m <= 64);
421
422    if (unlikely(nv50->gmtyprog)) {
423       BEGIN_RING(chan, RING_3D(GP_RESULT_MAP_SIZE), 1);
424       OUT_RING  (chan, m);
425       BEGIN_RING(chan, RING_3D(GP_RESULT_MAP(0)), n);
426       OUT_RINGp (chan, map, n);
427    } else {
428       BEGIN_RING(chan, RING_3D(VP_GP_BUILTIN_ATTR_EN), 1);
429       OUT_RING  (chan, vp->vp.attrs[2]);
430
431       BEGIN_RING(chan, RING_3D(MAP_SEMANTIC_4), 1);
432       OUT_RING  (chan, primid);
433
434       BEGIN_RING(chan, RING_3D(VP_RESULT_MAP_SIZE), 1);
435       OUT_RING  (chan, m);
436       BEGIN_RING(chan, RING_3D(VP_RESULT_MAP(0)), n);
437       OUT_RINGp (chan, map, n);
438    }
439
440    BEGIN_RING(chan, RING_3D(MAP_SEMANTIC_0), 4);
441    OUT_RING  (chan, colors);
442    OUT_RING  (chan, (vp->vp.clpd_nr << 8) | 4);
443    OUT_RING  (chan, 0);
444    OUT_RING  (chan, psiz);
445
446    BEGIN_RING(chan, RING_3D(FP_INTERPOLANT_CTRL), 1);
447    OUT_RING  (chan, interp);
448
449    nv50->state.interpolant_ctrl = interp;
450
451    nv50->state.semantic_color = colors;
452    nv50->state.semantic_psize = psiz;
453
454    BEGIN_RING(chan, RING_3D(NOPERSPECTIVE_BITMAP(0)), 4);
455    OUT_RINGp (chan, lin, 4);
456
457    BEGIN_RING(chan, RING_3D(GP_ENABLE), 1);
458    OUT_RING  (chan, nv50->gmtyprog ? 1 : 0);
459 }
460
461 static int
462 nv50_vp_gp_mapping(uint8_t *map, int m,
463                    struct nv50_program *vp, struct nv50_program *gp)
464 {
465    int i, j, c;
466
467    for (i = 0; i < gp->in_nr; ++i) {
468       uint8_t oid = 0, mv = 0, mg = gp->in[i].mask;
469
470       for (j = 0; j < vp->out_nr; ++j) {
471          if (vp->out[j].sn == gp->in[i].sn &&
472              vp->out[j].si == gp->in[i].si) {
473             mv = vp->out[j].mask;
474             oid = vp->out[j].hw;
475             break;
476          }
477       }
478
479       for (c = 0; c < 4; ++c, mv >>= 1, mg >>= 1) {
480          if (mg & mv & 1)
481             map[m++] = oid;
482          else
483          if (mg & 1)
484             map[m++] = (c == 3) ? 0x41 : 0x40;
485          oid += mv & 1;
486       }
487    }
488    return m;
489 }
490
491 void
492 nv50_gp_linkage_validate(struct nv50_context *nv50)
493 {
494    struct nouveau_channel *chan = nv50->screen->base.channel;
495    struct nv50_program *vp = nv50->vertprog;
496    struct nv50_program *gp = nv50->gmtyprog;
497    int m = 0;
498    int n;
499    uint8_t map[64];
500
501    if (!gp)
502       return;
503    memset(map, 0, sizeof(map));
504
505    m = nv50_vp_gp_mapping(map, m, vp, gp);
506
507    n = (m + 3) / 4;
508
509    BEGIN_RING(chan, RING_3D(VP_GP_BUILTIN_ATTR_EN), 1);
510    OUT_RING  (chan, vp->vp.attrs[2] | gp->vp.attrs[2]);
511
512    BEGIN_RING(chan, RING_3D(VP_RESULT_MAP_SIZE), 1);
513    OUT_RING  (chan, m);
514    BEGIN_RING(chan, RING_3D(VP_RESULT_MAP(0)), n);
515    OUT_RINGp (chan, map, n);
516 }