Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / drivers / nvc0 / nvc0_shader_state.c
1 /*
2  * Copyright 2010 Christoph Bumiller
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
23 #include "pipe/p_context.h"
24 #include "pipe/p_defines.h"
25 #include "pipe/p_state.h"
26 #include "util/u_inlines.h"
27
28 #include "nvc0_context.h"
29
30 static INLINE void
31 nvc0_program_update_context_state(struct nvc0_context *nvc0,
32                                   struct nvc0_program *prog, int stage)
33 {
34    if (prog->hdr[1])
35       nvc0->state.tls_required |= 1 << stage;
36    else
37       nvc0->state.tls_required &= ~(1 << stage);
38 }
39
40 static boolean
41 nvc0_program_validate(struct nvc0_context *nvc0, struct nvc0_program *prog)
42 {
43    int ret;
44    unsigned size;
45
46    if (prog->translated)
47       return TRUE;
48
49    prog->translated = nvc0_program_translate(prog);
50    if (!prog->translated)
51       return FALSE;
52
53    size = align(prog->code_size + NVC0_SHADER_HEADER_SIZE, 0x100);
54
55    ret = nouveau_resource_alloc(nvc0->screen->text_heap, size, prog,
56                                 &prog->res);
57    if (ret)
58       return FALSE;
59
60    prog->code_base = prog->res->start;
61
62    nvc0_m2mf_push_linear(&nvc0->base, nvc0->screen->text, prog->code_base,
63                          NOUVEAU_BO_VRAM, NVC0_SHADER_HEADER_SIZE, prog->hdr);
64    nvc0_m2mf_push_linear(&nvc0->base, nvc0->screen->text,
65                          prog->code_base + NVC0_SHADER_HEADER_SIZE,
66                          NOUVEAU_BO_VRAM, prog->code_size, prog->code);
67
68    BEGIN_RING(nvc0->screen->base.channel, RING_3D(MEM_BARRIER), 1);
69    OUT_RING  (nvc0->screen->base.channel, 0x1111);
70
71    return TRUE;
72 }
73
74 void
75 nvc0_vertprog_validate(struct nvc0_context *nvc0)
76 {
77    struct nouveau_channel *chan = nvc0->screen->base.channel;
78    struct nvc0_program *vp = nvc0->vertprog;
79
80    if (nvc0->clip.nr > vp->vp.num_ucps) {
81       assert(nvc0->clip.nr <= 6);
82       vp->vp.num_ucps = 6;
83
84       if (vp->translated)
85          nvc0_program_destroy(nvc0, vp);
86    }
87
88    if (!nvc0_program_validate(nvc0, vp))
89          return;
90    nvc0_program_update_context_state(nvc0, vp, 0);
91
92    BEGIN_RING(chan, RING_3D(SP_SELECT(1)), 2);
93    OUT_RING  (chan, 0x11);
94    OUT_RING  (chan, vp->code_base);
95    BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(1)), 1);
96    OUT_RING  (chan, vp->max_gpr);
97
98    // BEGIN_RING(chan, RING_3D_(0x163c), 1);
99    // OUT_RING  (chan, 0);
100 }
101
102 void
103 nvc0_fragprog_validate(struct nvc0_context *nvc0)
104 {
105    struct nouveau_channel *chan = nvc0->screen->base.channel;
106    struct nvc0_program *fp = nvc0->fragprog;
107
108    if (!nvc0_program_validate(nvc0, fp))
109          return;
110    nvc0_program_update_context_state(nvc0, fp, 4);
111
112    BEGIN_RING(chan, RING_3D(SP_SELECT(5)), 2);
113    OUT_RING  (chan, 0x51);
114    OUT_RING  (chan, fp->code_base);
115    BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(5)), 1);
116    OUT_RING  (chan, fp->max_gpr);
117
118    BEGIN_RING(chan, RING_3D_(0x0360), 2);
119    OUT_RING  (chan, 0x20164010);
120    OUT_RING  (chan, 0x20);
121    BEGIN_RING(chan, RING_3D_(0x196c), 1);
122    OUT_RING  (chan, fp->flags[0]);
123 }
124
125 void
126 nvc0_tctlprog_validate(struct nvc0_context *nvc0)
127 {
128    struct nouveau_channel *chan = nvc0->screen->base.channel;
129    struct nvc0_program *tp = nvc0->tctlprog;
130
131    if (!tp) {
132       BEGIN_RING(chan, RING_3D(SP_SELECT(2)), 1);
133       OUT_RING  (chan, 0x20);
134       return;
135    }
136    if (!nvc0_program_validate(nvc0, tp))
137          return;
138    nvc0_program_update_context_state(nvc0, tp, 1);
139
140    BEGIN_RING(chan, RING_3D(SP_SELECT(2)), 2);
141    OUT_RING  (chan, 0x21);
142    OUT_RING  (chan, tp->code_base);
143    BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(2)), 1);
144    OUT_RING  (chan, tp->max_gpr);   
145 }
146
147 void
148 nvc0_tevlprog_validate(struct nvc0_context *nvc0)
149 {
150    struct nouveau_channel *chan = nvc0->screen->base.channel;
151    struct nvc0_program *tp = nvc0->tevlprog;
152
153    if (!tp) {
154       BEGIN_RING(chan, RING_3D(TEP_SELECT), 1);
155       OUT_RING  (chan, 0x30);
156       return;
157    }
158    if (!nvc0_program_validate(nvc0, tp))
159          return;
160    nvc0_program_update_context_state(nvc0, tp, 2);
161
162    BEGIN_RING(chan, RING_3D(TEP_SELECT), 1);
163    OUT_RING  (chan, 0x31);
164    BEGIN_RING(chan, RING_3D(SP_START_ID(3)), 1);
165    OUT_RING  (chan, tp->code_base);
166    BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(3)), 1);
167    OUT_RING  (chan, tp->max_gpr);   
168 }
169
170 void
171 nvc0_gmtyprog_validate(struct nvc0_context *nvc0)
172 {
173    struct nouveau_channel *chan = nvc0->screen->base.channel;
174    struct nvc0_program *gp = nvc0->gmtyprog;
175
176    if (!gp) {
177       BEGIN_RING(chan, RING_3D(GP_SELECT), 1);
178       OUT_RING  (chan, 0x40);
179       return;
180    }
181    if (!nvc0_program_validate(nvc0, gp))
182          return;
183    nvc0_program_update_context_state(nvc0, gp, 3);
184
185    BEGIN_RING(chan, RING_3D(GP_SELECT), 1);
186    OUT_RING  (chan, 0x41);
187    BEGIN_RING(chan, RING_3D(SP_START_ID(4)), 1);
188    OUT_RING  (chan, gp->code_base);
189    BEGIN_RING(chan, RING_3D(SP_GPR_ALLOC(4)), 1);
190    OUT_RING  (chan, gp->max_gpr);   
191 }
192
193 /* It's *is* kind of shader related. We need to inspect the program
194  * to get the output locations right.
195  */
196 void
197 nvc0_tfb_validate(struct nvc0_context *nvc0)
198 {
199    struct nouveau_channel *chan = nvc0->screen->base.channel;
200    struct nvc0_program *vp;
201    struct nvc0_transform_feedback_state *tfb = nvc0->tfb;
202    int b;
203
204    BEGIN_RING(chan, RING_3D(TFB_ENABLE), 1);
205    if (!tfb) {
206       OUT_RING(chan, 0);
207       return;
208    }
209    OUT_RING(chan, 1);
210
211    vp = nvc0->vertprog ? nvc0->vertprog : nvc0->gmtyprog;
212
213    for (b = 0; b < nvc0->num_tfbbufs; ++b) {
214       uint8_t idx, var[128];
215       int i, n;
216       struct nv04_resource *buf = nv04_resource(nvc0->tfbbuf[b]);
217
218       BEGIN_RING(chan, RING_3D(TFB_BUFFER_ENABLE(b)), 5);
219       OUT_RING  (chan, 1);
220       OUT_RESRCh(chan, buf, nvc0->tfb_offset[b], NOUVEAU_BO_WR);
221       OUT_RESRCl(chan, buf, nvc0->tfb_offset[b], NOUVEAU_BO_WR);
222       OUT_RING  (chan, buf->base.width0 - nvc0->tfb_offset[b]);
223       OUT_RING  (chan, 0); /* TFB_PRIMITIVE_ID <- offset ? */
224
225       if (!(nvc0->dirty & NVC0_NEW_TFB))
226          continue;
227
228       BEGIN_RING(chan, RING_3D(TFB_UNK07X0(b)), 3);
229       OUT_RING  (chan, 0);
230       OUT_RING  (chan, tfb->varying_count[b]);
231       OUT_RING  (chan, tfb->stride[b]);
232
233       n = b ? tfb->varying_count[b - 1] : 0;
234       i = 0;
235       for (; i < tfb->varying_count[b]; ++i) {
236          idx = tfb->varying_index[n + i];
237          var[i] = vp->vp.out_pos[idx >> 2] + (idx & 3);
238       }
239       for (; i & 3; ++i)
240          var[i] = 0;
241
242       BEGIN_RING(chan, RING_3D(TFB_VARYING_LOCS(b, 0)), i / 4);
243       OUT_RINGp (chan, var, i / 4);
244    }
245    for (; b < 4; ++b)
246       IMMED_RING(chan, RING_3D(TFB_BUFFER_ENABLE(b)), 0);
247 }