2 * Copyright 2008 Ben Skeggs
3 * Copyright 2010 Christoph Bumiller
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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
24 #include "pipe/p_context.h"
25 #include "pipe/p_defines.h"
26 #include "pipe/p_state.h"
27 #include "util/u_inlines.h"
29 #include "nv50_context.h"
32 nv50_constbufs_validate(struct nv50_context
*nv50
)
34 struct nouveau_pushbuf
*push
= nv50
->base
.pushbuf
;
37 for (s
= 0; s
< 3; ++s
) {
38 struct nv04_resource
*res
;
42 if (s
== PIPE_SHADER_FRAGMENT
)
43 p
= NV50_3D_SET_PROGRAM_CB_PROGRAM_FRAGMENT
;
45 if (s
== PIPE_SHADER_GEOMETRY
)
46 p
= NV50_3D_SET_PROGRAM_CB_PROGRAM_GEOMETRY
;
48 p
= NV50_3D_SET_PROGRAM_CB_PROGRAM_VERTEX
;
50 while (nv50
->constbuf_dirty
[s
]) {
51 struct nouveau_bo
*bo
;
55 i
= ffs(nv50
->constbuf_dirty
[s
]) - 1;
56 nv50
->constbuf_dirty
[s
] &= ~(1 << i
);
58 res
= nv04_resource(nv50
->constbuf
[s
][i
]);
61 BEGIN_NV04(push
, NV50_3D(SET_PROGRAM_CB
), 1);
62 PUSH_DATA (push
, (i
<< 8) | p
| 0);
70 /* always upload GL uniforms through CB DATA */
71 bo
= nv50
->screen
->uniforms
;
72 words
= res
->base
.width0
/ 4;
78 if (!nouveau_resource_mapped_by_gpu(&res
->base
)) {
79 nouveau_buffer_migrate(&nv50
->base
, res
, NOUVEAU_BO_VRAM
);
81 BEGIN_NV04(push
, NV50_3D(CODE_CB_FLUSH
), 1);
84 BEGIN_NV04(push
, NV50_3D(CB_DEF_ADDRESS_HIGH
), 3);
85 PUSH_DATAh(push
, res
->address
);
86 PUSH_DATA (push
, res
->address
);
87 PUSH_DATA (push
, (b
<< 16) | (res
->base
.width0
& 0xffff));
88 BEGIN_NV04(push
, NV50_3D(SET_PROGRAM_CB
), 1);
89 PUSH_DATA (push
, (b
<< 12) | (i
<< 8) | p
| 1);
94 if (bo
!= nv50
->screen
->uniforms
)
95 BCTX_REFN(nv50
->bufctx_3d
, CB(s
, i
), res
, RD
);
100 if (!PUSH_SPACE(push
, 16))
102 nr
= PUSH_AVAIL(push
);
104 nr
= MIN2(MIN2(nr
- 3, words
), NV04_PFIFO_MAX_PACKET_LEN
);
106 BEGIN_NV04(push
, NV50_3D(CB_ADDR
), 1);
107 PUSH_DATA (push
, (start
<< 8) | b
);
108 BEGIN_NI04(push
, NV50_3D(CB_DATA(0)), nr
);
109 PUSH_DATAp(push
, &res
->data
[start
* 4], nr
);
119 nv50_program_validate(struct nv50_context
*nv50
, struct nv50_program
*prog
)
121 struct nouveau_heap
*heap
;
125 if (!prog
->translated
) {
126 prog
->translated
= nv50_program_translate(prog
);
127 if (!prog
->translated
)
133 if (prog
->type
== PIPE_SHADER_FRAGMENT
) heap
= nv50
->screen
->fp_code_heap
;
135 if (prog
->type
== PIPE_SHADER_GEOMETRY
) heap
= nv50
->screen
->gp_code_heap
;
137 heap
= nv50
->screen
->vp_code_heap
;
139 size
= align(prog
->code_size
, 0x100);
141 ret
= nouveau_heap_alloc(heap
, size
, prog
, &prog
->mem
);
143 NOUVEAU_ERR("out of code space for shader type %i\n", prog
->type
);
146 prog
->code_base
= prog
->mem
->start
;
148 nv50_relocate_program(prog
, prog
->code_base
, 0);
150 nv50_sifc_linear_u8(&nv50
->base
, nv50
->screen
->code
,
151 (prog
->type
<< NV50_CODE_BO_SIZE_LOG2
) + prog
->code_base
,
152 NOUVEAU_BO_VRAM
, prog
->code_size
, prog
->code
);
154 BEGIN_NV04(nv50
->base
.pushbuf
, NV50_3D(CODE_CB_FLUSH
), 1);
155 PUSH_DATA (nv50
->base
.pushbuf
, 0);
161 nv50_program_update_context_state(struct nv50_context
*nv50
,
162 struct nv50_program
*prog
, int stage
)
164 const unsigned flags
= NOUVEAU_BO_VRAM
| NOUVEAU_BO_RDWR
;
166 if (prog
&& prog
->uses_lmem
) {
167 if (!nv50
->state
.tls_required
)
168 BCTX_REFN_bo(nv50
->bufctx_3d
, TLS
, flags
, nv50
->screen
->tls_bo
);
169 nv50
->state
.tls_required
|= 1 << stage
;
171 if (nv50
->state
.tls_required
== (1 << stage
))
172 nouveau_bufctx_reset(nv50
->bufctx_3d
, NV50_BIND_TLS
);
173 nv50
->state
.tls_required
&= ~(1 << stage
);
178 nv50_vertprog_validate(struct nv50_context
*nv50
)
180 struct nouveau_pushbuf
*push
= nv50
->base
.pushbuf
;
181 struct nv50_program
*vp
= nv50
->vertprog
;
183 if (!nv50_program_validate(nv50
, vp
))
185 nv50_program_update_context_state(nv50
, vp
, 0);
187 BEGIN_NV04(push
, NV50_3D(VP_ATTR_EN(0)), 2);
188 PUSH_DATA (push
, vp
->vp
.attrs
[0]);
189 PUSH_DATA (push
, vp
->vp
.attrs
[1]);
190 BEGIN_NV04(push
, NV50_3D(VP_REG_ALLOC_RESULT
), 1);
191 PUSH_DATA (push
, vp
->max_out
);
192 BEGIN_NV04(push
, NV50_3D(VP_REG_ALLOC_TEMP
), 1);
193 PUSH_DATA (push
, vp
->max_gpr
);
194 BEGIN_NV04(push
, NV50_3D(VP_START_ID
), 1);
195 PUSH_DATA (push
, vp
->code_base
);
199 nv50_fragprog_validate(struct nv50_context
*nv50
)
201 struct nouveau_pushbuf
*push
= nv50
->base
.pushbuf
;
202 struct nv50_program
*fp
= nv50
->fragprog
;
204 if (!nv50_program_validate(nv50
, fp
))
206 nv50_program_update_context_state(nv50
, fp
, 1);
208 BEGIN_NV04(push
, NV50_3D(FP_REG_ALLOC_TEMP
), 1);
209 PUSH_DATA (push
, fp
->max_gpr
);
210 BEGIN_NV04(push
, NV50_3D(FP_RESULT_COUNT
), 1);
211 PUSH_DATA (push
, fp
->max_out
);
212 BEGIN_NV04(push
, NV50_3D(FP_CONTROL
), 1);
213 PUSH_DATA (push
, fp
->fp
.flags
[0]);
214 BEGIN_NV04(push
, NV50_3D(FP_CTRL_UNK196C
), 1);
215 PUSH_DATA (push
, fp
->fp
.flags
[1]);
216 BEGIN_NV04(push
, NV50_3D(FP_START_ID
), 1);
217 PUSH_DATA (push
, fp
->code_base
);
221 nv50_gmtyprog_validate(struct nv50_context
*nv50
)
223 struct nouveau_pushbuf
*push
= nv50
->base
.pushbuf
;
224 struct nv50_program
*gp
= nv50
->gmtyprog
;
227 BEGIN_NV04(push
, NV50_3D(GP_REG_ALLOC_TEMP
), 1);
228 PUSH_DATA (push
, gp
->max_gpr
);
229 BEGIN_NV04(push
, NV50_3D(GP_REG_ALLOC_RESULT
), 1);
230 PUSH_DATA (push
, gp
->max_out
);
231 BEGIN_NV04(push
, NV50_3D(GP_OUTPUT_PRIMITIVE_TYPE
), 1);
232 PUSH_DATA (push
, gp
->gp
.prim_type
);
233 BEGIN_NV04(push
, NV50_3D(GP_VERTEX_OUTPUT_COUNT
), 1);
234 PUSH_DATA (push
, gp
->gp
.vert_count
);
235 BEGIN_NV04(push
, NV50_3D(GP_START_ID
), 1);
236 PUSH_DATA (push
, gp
->code_base
);
238 nv50_program_update_context_state(nv50
, gp
, 2);
240 /* GP_ENABLE is updated in linkage validation */
244 nv50_sprite_coords_validate(struct nv50_context
*nv50
)
246 struct nouveau_pushbuf
*push
= nv50
->base
.pushbuf
;
247 uint32_t pntc
[8], mode
;
248 struct nv50_program
*fp
= nv50
->fragprog
;
250 unsigned m
= (nv50
->state
.interpolant_ctrl
>> 8) & 0xff;
252 if (!nv50
->rast
->pipe
.point_quad_rasterization
) {
253 if (nv50
->state
.point_sprite
) {
254 BEGIN_NV04(push
, NV50_3D(POINT_COORD_REPLACE_MAP(0)), 8);
255 for (i
= 0; i
< 8; ++i
)
258 nv50
->state
.point_sprite
= FALSE
;
262 nv50
->state
.point_sprite
= TRUE
;
265 memset(pntc
, 0, sizeof(pntc
));
267 for (i
= 0; i
< fp
->in_nr
; i
++) {
268 unsigned n
= util_bitcount(fp
->in
[i
].mask
);
270 if (fp
->in
[i
].sn
!= TGSI_SEMANTIC_GENERIC
) {
274 if (!(nv50
->rast
->pipe
.sprite_coord_enable
& (1 << fp
->in
[i
].si
))) {
279 for (c
= 0; c
< 4; ++c
) {
280 if (fp
->in
[i
].mask
& (1 << c
)) {
281 pntc
[m
/ 8] |= (c
+ 1) << ((m
% 8) * 4);
287 if (nv50
->rast
->pipe
.sprite_coord_mode
== PIPE_SPRITE_COORD_LOWER_LEFT
)
292 BEGIN_NV04(push
, NV50_3D(POINT_SPRITE_CTRL
), 1);
293 PUSH_DATA (push
, mode
);
295 BEGIN_NV04(push
, NV50_3D(POINT_COORD_REPLACE_MAP(0)), 8);
296 PUSH_DATAp(push
, pntc
, 8);
299 /* Validate state derived from shaders and the rasterizer cso. */
301 nv50_validate_derived_rs(struct nv50_context
*nv50
)
303 struct nouveau_pushbuf
*push
= nv50
->base
.pushbuf
;
304 uint32_t color
, psize
;
306 nv50_sprite_coords_validate(nv50
);
308 if (nv50
->dirty
& NV50_NEW_FRAGPROG
)
310 psize
= nv50
->state
.semantic_psize
& ~NV50_3D_SEMANTIC_PTSZ_PTSZ_EN__MASK
;
311 color
= nv50
->state
.semantic_color
& ~NV50_3D_SEMANTIC_COLOR_CLMP_EN
;
313 if (nv50
->rast
->pipe
.clamp_vertex_color
)
314 color
|= NV50_3D_SEMANTIC_COLOR_CLMP_EN
;
316 if (color
!= nv50
->state
.semantic_color
) {
317 nv50
->state
.semantic_color
= color
;
318 BEGIN_NV04(push
, NV50_3D(SEMANTIC_COLOR
), 1);
319 PUSH_DATA (push
, color
);
322 if (nv50
->rast
->pipe
.point_size_per_vertex
)
323 psize
|= NV50_3D_SEMANTIC_PTSZ_PTSZ_EN__MASK
;
325 if (psize
!= nv50
->state
.semantic_psize
) {
326 nv50
->state
.semantic_psize
= psize
;
327 BEGIN_NV04(push
, NV50_3D(SEMANTIC_PTSZ
), 1);
328 PUSH_DATA (push
, psize
);
333 nv50_vec4_map(uint8_t *map
, int mid
, uint32_t lin
[4],
334 struct nv50_varying
*in
, struct nv50_varying
*out
)
337 uint8_t mv
= out
->mask
, mf
= in
->mask
, oid
= out
->hw
;
339 for (c
= 0; c
< 4; ++c
) {
342 lin
[mid
/ 32] |= 1 << (mid
% 32);
360 nv50_fp_linkage_validate(struct nv50_context
*nv50
)
362 struct nouveau_pushbuf
*push
= nv50
->base
.pushbuf
;
363 struct nv50_program
*vp
= nv50
->gmtyprog
? nv50
->gmtyprog
: nv50
->vertprog
;
364 struct nv50_program
*fp
= nv50
->fragprog
;
365 struct nv50_varying dummy
;
368 uint32_t psiz
= 0x000;
369 uint32_t interp
= fp
->fp
.interp
;
370 uint32_t colors
= fp
->fp
.colors
;
374 memset(lin
, 0x00, sizeof(lin
));
376 /* XXX: in buggy-endian mode, is the first element of map (u32)0x000000xx
377 * or is it the first byte ?
379 memset(map
, nv50
->gmtyprog
? 0x80 : 0x40, sizeof(map
));
381 dummy
.mask
= 0xf; /* map all components of HPOS */
383 m
= nv50_vec4_map(map
, 0, lin
, &dummy
, &vp
->out
[0]);
385 for (c
= 0; c
< vp
->vp
.clpd_nr
; ++c
)
386 map
[m
++] = vp
->vp
.clpd
+ c
;
388 colors
|= m
<< 8; /* adjust BFC0 id */
390 /* if light_twoside is active, FFC0_ID == BFC0_ID is invalid */
391 if (nv50
->rast
->pipe
.light_twoside
) {
392 for (i
= 0; i
< 2; ++i
)
393 m
= nv50_vec4_map(map
, m
, lin
,
394 &fp
->in
[fp
->vp
.bfc
[i
]], &vp
->out
[vp
->vp
.bfc
[i
]]);
396 colors
+= m
- 4; /* adjust FFC0 id */
397 interp
|= m
<< 8; /* set map id where 'normal' FP inputs start */
400 for (i
= 0; i
< fp
->in_nr
; ++i
) {
401 for (n
= 0; n
< vp
->out_nr
; ++n
)
402 if (vp
->out
[n
].sn
== fp
->in
[i
].sn
&&
403 vp
->out
[n
].si
== fp
->in
[i
].si
)
405 m
= nv50_vec4_map(map
, m
, lin
,
406 &fp
->in
[i
], (n
< vp
->out_nr
) ? &vp
->out
[n
] : &dummy
);
409 /* PrimitiveID either is replaced by the system value, or
410 * written by the geometry shader into an output register
412 if (fp
->gp
.primid
< 0x40) {
414 map
[m
++] = vp
->gp
.primid
;
417 if (nv50
->rast
->pipe
.point_size_per_vertex
) {
419 map
[m
++] = vp
->vp
.psiz
;
422 if (nv50
->rast
->pipe
.clamp_vertex_color
)
423 colors
|= NV50_3D_SEMANTIC_COLOR_CLMP_EN
;
428 if (unlikely(nv50
->gmtyprog
)) {
429 BEGIN_NV04(push
, NV50_3D(GP_RESULT_MAP_SIZE
), 1);
431 BEGIN_NV04(push
, NV50_3D(GP_RESULT_MAP(0)), n
);
432 PUSH_DATAp(push
, map
, n
);
434 BEGIN_NV04(push
, NV50_3D(VP_GP_BUILTIN_ATTR_EN
), 1);
435 PUSH_DATA (push
, vp
->vp
.attrs
[2]);
437 BEGIN_NV04(push
, NV50_3D(SEMANTIC_PRIM_ID
), 1);
438 PUSH_DATA (push
, primid
);
440 BEGIN_NV04(push
, NV50_3D(VP_RESULT_MAP_SIZE
), 1);
442 BEGIN_NV04(push
, NV50_3D(VP_RESULT_MAP(0)), n
);
443 PUSH_DATAp(push
, map
, n
);
446 BEGIN_NV04(push
, NV50_3D(SEMANTIC_COLOR
), 4);
447 PUSH_DATA (push
, colors
);
448 PUSH_DATA (push
, (vp
->vp
.clpd_nr
<< 8) | 4);
450 PUSH_DATA (push
, psiz
);
452 BEGIN_NV04(push
, NV50_3D(FP_INTERPOLANT_CTRL
), 1);
453 PUSH_DATA (push
, interp
);
455 nv50
->state
.interpolant_ctrl
= interp
;
457 nv50
->state
.semantic_color
= colors
;
458 nv50
->state
.semantic_psize
= psiz
;
460 BEGIN_NV04(push
, NV50_3D(NOPERSPECTIVE_BITMAP(0)), 4);
461 PUSH_DATAp(push
, lin
, 4);
463 BEGIN_NV04(push
, NV50_3D(GP_ENABLE
), 1);
464 PUSH_DATA (push
, nv50
->gmtyprog
? 1 : 0);
468 nv50_vp_gp_mapping(uint8_t *map
, int m
,
469 struct nv50_program
*vp
, struct nv50_program
*gp
)
473 for (i
= 0; i
< gp
->in_nr
; ++i
) {
474 uint8_t oid
= 0, mv
= 0, mg
= gp
->in
[i
].mask
;
476 for (j
= 0; j
< vp
->out_nr
; ++j
) {
477 if (vp
->out
[j
].sn
== gp
->in
[i
].sn
&&
478 vp
->out
[j
].si
== gp
->in
[i
].si
) {
479 mv
= vp
->out
[j
].mask
;
485 for (c
= 0; c
< 4; ++c
, mv
>>= 1, mg
>>= 1) {
490 map
[m
++] = (c
== 3) ? 0x41 : 0x40;
498 nv50_gp_linkage_validate(struct nv50_context
*nv50
)
500 struct nouveau_pushbuf
*push
= nv50
->base
.pushbuf
;
501 struct nv50_program
*vp
= nv50
->vertprog
;
502 struct nv50_program
*gp
= nv50
->gmtyprog
;
509 memset(map
, 0, sizeof(map
));
511 m
= nv50_vp_gp_mapping(map
, m
, vp
, gp
);
515 BEGIN_NV04(push
, NV50_3D(VP_GP_BUILTIN_ATTR_EN
), 1);
516 PUSH_DATA (push
, vp
->vp
.attrs
[2] | gp
->vp
.attrs
[2]);
518 BEGIN_NV04(push
, NV50_3D(VP_RESULT_MAP_SIZE
), 1);
520 BEGIN_NV04(push
, NV50_3D(VP_RESULT_MAP(0)), n
);
521 PUSH_DATAp(push
, map
, n
);