1 /**************************************************************************
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
34 #include "tnl/t_context.h"
35 #include "intel_batchbuffer.h"
38 #include "i915_context.h"
39 #include "i915_program.h"
41 static GLuint
translate_tex_src_bit( struct i915_fragment_program
*p
,
45 case TEXTURE_1D_BIT
: return D0_SAMPLE_TYPE_2D
;
46 case TEXTURE_2D_BIT
: return D0_SAMPLE_TYPE_2D
;
47 case TEXTURE_RECT_BIT
: return D0_SAMPLE_TYPE_2D
;
48 case TEXTURE_3D_BIT
: return D0_SAMPLE_TYPE_VOLUME
;
49 case TEXTURE_CUBE_BIT
: return D0_SAMPLE_TYPE_CUBE
;
50 default: i915_program_error(p
, "TexSrcBit"); return 0;
54 static GLuint
get_source( struct i915_fragment_program
*p
,
55 GLenum src
, GLuint unit
)
59 if (p
->src_texture
== UREG_BAD
) {
61 /* TODO: Use D0_CHANNEL_XY where possible.
63 GLuint dim
= translate_tex_src_bit( p
, p
->ctx
->Texture
.Unit
[unit
]._ReallyEnabled
);
64 GLuint sampler
= i915_emit_decl(p
, REG_TYPE_S
, unit
, dim
);
65 GLuint texcoord
= i915_emit_decl(p
, REG_TYPE_T
, unit
, D0_CHANNEL_ALL
);
66 GLuint tmp
= i915_get_temp( p
);
69 if (p
->VB
->TexCoordPtr
[unit
]->size
== 4)
72 p
->src_texture
= i915_emit_texld( p
, tmp
, A0_DEST_CHANNEL_ALL
,
73 sampler
, texcoord
, op
);
76 return p
->src_texture
;
78 return i915_emit_const4fv( p
, p
->ctx
->Texture
.Unit
[unit
].EnvColor
);
79 case GL_PRIMARY_COLOR
:
80 return i915_emit_decl(p
, REG_TYPE_T
, T_DIFFUSE
, D0_CHANNEL_ALL
);
84 GET_UREG_TYPE(p
->src_previous
),
85 GET_UREG_NR(p
->src_previous
), D0_CHANNEL_ALL
);
86 return p
->src_previous
;
91 static GLuint
emit_combine_source( struct i915_fragment_program
*p
,
99 src
= get_source(p
, source
, unit
);
102 case GL_ONE_MINUS_SRC_COLOR
:
104 * Emit tmp = 1.0 + arg.-x-y-z-w
106 arg
= i915_get_temp( p
);
107 return i915_emit_arith( p
, A0_ADD
, arg
, mask
, 0,
108 swizzle(src
, ONE
, ONE
, ONE
, ONE
),
109 negate(src
, 1,1,1,1), 0);
112 if (mask
== A0_DEST_CHANNEL_W
)
115 return swizzle( src
, W
, W
, W
, W
);
116 case GL_ONE_MINUS_SRC_ALPHA
:
118 * Emit tmp = 1.0 + arg.-w-w-w-w
120 arg
= i915_get_temp( p
);
121 return i915_emit_arith( p
, A0_ADD
, arg
, mask
, 0,
122 swizzle(src
, ONE
, ONE
, ONE
, ONE
),
123 negate( swizzle(src
,W
,W
,W
,W
), 1,1,1,1), 0);
132 static int nr_args( GLenum mode
)
135 case GL_REPLACE
: return 1;
136 case GL_MODULATE
: return 2;
137 case GL_ADD
: return 2;
138 case GL_ADD_SIGNED
: return 2;
139 case GL_INTERPOLATE
: return 3;
140 case GL_SUBTRACT
: return 2;
141 case GL_DOT3_RGB_EXT
: return 2;
142 case GL_DOT3_RGBA_EXT
: return 2;
143 case GL_DOT3_RGB
: return 2;
144 case GL_DOT3_RGBA
: return 2;
150 static GLboolean
args_match( struct gl_texture_unit
*texUnit
)
152 int i
, nr
= nr_args(texUnit
->Combine
.ModeRGB
);
154 for (i
= 0 ; i
< nr
; i
++) {
155 if (texUnit
->Combine
.SourceA
[i
] != texUnit
->Combine
.SourceRGB
[i
])
158 switch(texUnit
->Combine
.OperandA
[i
]) {
160 switch(texUnit
->Combine
.OperandRGB
[i
]) {
168 case GL_ONE_MINUS_SRC_ALPHA
:
169 switch(texUnit
->Combine
.OperandRGB
[i
]) {
170 case GL_ONE_MINUS_SRC_COLOR
:
171 case GL_ONE_MINUS_SRC_ALPHA
:
178 return GL_FALSE
; /* impossible */
186 static GLuint
emit_combine( struct i915_fragment_program
*p
,
192 const GLenum
*source
,
193 const GLenum
*operand
)
195 int tmp
, src
[3], nr
= nr_args(mode
);
198 for (i
= 0; i
< nr
; i
++)
199 src
[i
] = emit_combine_source( p
, mask
, unit
, source
[i
], operand
[i
] );
203 if (mask
== A0_DEST_CHANNEL_ALL
&& !saturate
)
206 return i915_emit_arith( p
, A0_MOV
, dest
, mask
, saturate
, src
[0], 0, 0 );
208 return i915_emit_arith( p
, A0_MUL
, dest
, mask
, saturate
,
211 return i915_emit_arith( p
, A0_ADD
, dest
, mask
, saturate
,
217 tmp
= i915_emit_const1f(p
, .5);
218 tmp
= negate(swizzle(tmp
,X
,X
,X
,X
),1,1,1,1);
219 i915_emit_arith( p
, A0_ADD
, dest
, mask
, 0, src
[0], src
[1], 0 );
220 i915_emit_arith( p
, A0_ADD
, dest
, mask
, saturate
, dest
, tmp
, 0 );
222 case GL_INTERPOLATE
: /* TWO INSTRUCTIONS */
223 /* Arg0 * (Arg2) + Arg1 * (1-Arg2)
225 * Arg0*Arg2 + Arg1 - Arg1Arg2
227 * tmp = Arg0*Arg2 + Arg1,
228 * result = (-Arg1)Arg2 + tmp
230 tmp
= i915_get_temp( p
);
231 i915_emit_arith( p
, A0_MAD
, tmp
, mask
, 0, src
[0], src
[2], src
[1] );
232 i915_emit_arith( p
, A0_MAD
, dest
, mask
, saturate
,
233 negate(src
[1], 1,1,1,1), src
[2], tmp
);
237 return i915_emit_arith( p
, A0_ADD
, dest
, mask
, saturate
, src
[0],
238 negate(src
[1],1,1,1,1), 0 );
241 case GL_DOT3_RGBA_EXT
:
242 case GL_DOT3_RGB_EXT
:
244 GLuint tmp0
= i915_get_temp( p
);
245 GLuint tmp1
= i915_get_temp( p
);
246 GLuint neg1
= negate(swizzle(i915_emit_const1f(p
, 1),X
,X
,X
,X
), 1,1,1,1);
247 GLuint two
= swizzle(i915_emit_const1f(p
, 2),X
,X
,X
,X
);
248 i915_emit_arith( p
, A0_MAD
, tmp0
, A0_DEST_CHANNEL_ALL
, 0,
250 if (src
[0] == src
[1])
253 i915_emit_arith( p
, A0_MAD
, tmp1
, A0_DEST_CHANNEL_ALL
, 0,
255 i915_emit_arith( p
, A0_DP3
, dest
, mask
, saturate
, tmp0
, tmp1
, 0);
264 static GLuint
get_dest( struct i915_fragment_program
*p
, int unit
)
266 if (p
->ctx
->_TriangleCaps
& DD_SEPARATE_SPECULAR
)
267 return i915_get_temp( p
);
268 else if (unit
!= p
->last_tex_stage
)
269 return i915_get_temp( p
);
271 return UREG(REG_TYPE_OC
, 0);
276 static GLuint
emit_texenv( struct i915_fragment_program
*p
, int unit
)
278 struct gl_texture_unit
*texUnit
= &p
->ctx
->Texture
.Unit
[unit
];
279 GLenum envMode
= texUnit
->EnvMode
;
280 struct gl_texture_object
*tObj
= texUnit
->_Current
;
281 GLenum format
= tObj
->Image
[0][tObj
->BaseLevel
]->Format
;
282 GLuint saturate
= unit
< p
->last_tex_stage
? A0_DEST_SATURATE
: 0;
286 const int cf
= get_source(p
, GL_PREVIOUS
, unit
);
287 const int cc
= get_source(p
, GL_CONSTANT
, unit
);
288 const int cs
= get_source(p
, GL_TEXTURE
, unit
);
289 const int out
= get_dest(p
, unit
);
291 if (format
== GL_INTENSITY
) {
292 /* cv = cf(1 - cs) + cc.cs
293 * cv = cf - cf.cs + cc.cs
295 /* u[2] = MAD( -cf * cs + cf )
296 * cv = MAD( cc * cs + u[2] )
299 i915_emit_arith( p
, A0_MAD
, out
, A0_DEST_CHANNEL_ALL
, 0,
300 negate(cf
,1,1,1,1), cs
, cf
);
302 i915_emit_arith( p
, A0_MAD
, out
, A0_DEST_CHANNEL_ALL
, saturate
,
307 /* cv = cf(1 - cs) + cc.cs
308 * cv = cf - cf.cs + cc.cs
311 /* u[2] = MAD( cf.-x-y-zw * cs.xyzw + cf.xyz0 )
312 * oC = MAD( cc.xyz0 * cs.xyz0 + u[2].xyzw )
314 i915_emit_arith( p
, A0_MAD
, out
, A0_DEST_CHANNEL_ALL
, 0,
317 swizzle(cf
,X
,Y
,Z
,ZERO
) );
320 i915_emit_arith( p
, A0_MAD
, out
, A0_DEST_CHANNEL_ALL
, saturate
,
321 swizzle(cc
,X
,Y
,Z
,ZERO
),
322 swizzle(cs
,X
,Y
,Z
,ZERO
),
330 if (format
== GL_RGB
||
332 int cf
= get_source( p
, GL_PREVIOUS
, unit
);
333 int cs
= get_source( p
, GL_TEXTURE
, unit
);
334 int out
= get_dest(p
, unit
);
336 /* cv = cf(1-as) + cs.as
337 * cv = cf.(-as) + cf + cs.as
341 /* u[2] = mad( cf.xyzw * cs.-w-w-w1 + cf.xyz0 )
342 * oc = mad( cs.xyz0 * cs.www0 + u[2].xyzw )
344 i915_emit_arith( p
, A0_MAD
, out
, A0_DEST_CHANNEL_ALL
, 0,
346 negate(swizzle(cs
,W
,W
,W
,ONE
),1,1,1,0),
347 swizzle(cf
,X
,Y
,Z
,ZERO
) );
349 i915_emit_arith( p
, A0_MAD
, out
, A0_DEST_CHANNEL_ALL
, saturate
,
350 swizzle(cs
,X
,Y
,Z
,ZERO
),
351 swizzle(cs
,W
,W
,W
,ZERO
),
356 return get_source( p
, GL_PREVIOUS
, unit
);
361 const int cs
= get_source( p
, GL_TEXTURE
, unit
); /* saturated */
364 const int cf
= get_source( p
, GL_PREVIOUS
, unit
); /* saturated */
365 i915_emit_arith( p
, A0_MOV
, cs
, A0_DEST_CHANNEL_XYZ
, 0, cf
, 0, 0 );
370 const int cf
= get_source( p
, GL_PREVIOUS
, unit
); /* saturated */
371 i915_emit_arith( p
, A0_MOV
, cs
, A0_DEST_CHANNEL_W
, 0, cf
, 0, 0 );
380 const int cf
= get_source( p
, GL_PREVIOUS
, unit
);
381 const int cs
= get_source( p
, GL_TEXTURE
, unit
);
382 const int out
= get_dest(p
, unit
);
385 i915_emit_arith( p
, A0_MUL
, out
, A0_DEST_CHANNEL_ALL
, saturate
,
386 swizzle(cs
, ONE
, ONE
, ONE
, W
), cf
, 0 );
389 i915_emit_arith( p
, A0_MUL
, out
, A0_DEST_CHANNEL_ALL
, saturate
,
396 int cf
= get_source( p
, GL_PREVIOUS
, unit
);
397 int cs
= get_source( p
, GL_TEXTURE
, unit
);
398 const int out
= get_dest( p
, unit
);
400 if (format
== GL_INTENSITY
) {
401 /* output-color.rgba = add( incoming, u[1] )
403 i915_emit_arith( p
, A0_ADD
, out
, A0_DEST_CHANNEL_ALL
, saturate
,
408 /* cv.xyz = cf.xyz + cs.xyz
411 * cv.xyzw = MAD( cf.111w * cs.xyzw + cf.xyz0 )
413 i915_emit_arith( p
, A0_MAD
, out
, A0_DEST_CHANNEL_ALL
, saturate
,
414 swizzle(cf
,ONE
,ONE
,ONE
,W
),
416 swizzle(cf
,X
,Y
,Z
,ZERO
) );
422 GLuint rgb_shift
, alpha_shift
, out
, shift
;
423 GLuint dest
= get_dest(p
, unit
);
425 /* The EXT version of the DOT3 extension does not support the
426 * scale factor, but the ARB version (and the version in OpenGL
429 switch (texUnit
->Combine
.ModeRGB
) {
430 case GL_DOT3_RGB_EXT
:
431 alpha_shift
= texUnit
->Combine
.ScaleShiftA
;
435 case GL_DOT3_RGBA_EXT
:
441 rgb_shift
= texUnit
->Combine
.ScaleShiftRGB
;
442 alpha_shift
= texUnit
->Combine
.ScaleShiftA
;
447 /* Emit the RGB and A combine ops
449 if (texUnit
->Combine
.ModeRGB
== texUnit
->Combine
.ModeA
&&
450 args_match( texUnit
)) {
451 out
= emit_combine( p
, dest
, A0_DEST_CHANNEL_ALL
, saturate
,
453 texUnit
->Combine
.ModeRGB
,
454 texUnit
->Combine
.SourceRGB
,
455 texUnit
->Combine
.OperandRGB
);
457 else if (texUnit
->Combine
.ModeRGB
== GL_DOT3_RGBA_EXT
||
458 texUnit
->Combine
.ModeRGB
== GL_DOT3_RGBA
) {
460 out
= emit_combine( p
, dest
, A0_DEST_CHANNEL_ALL
, saturate
,
462 texUnit
->Combine
.ModeRGB
,
463 texUnit
->Combine
.SourceRGB
,
464 texUnit
->Combine
.OperandRGB
);
467 /* Need to do something to stop from re-emitting identical
468 * argument calculations here:
470 out
= emit_combine( p
, dest
, A0_DEST_CHANNEL_XYZ
, saturate
,
472 texUnit
->Combine
.ModeRGB
,
473 texUnit
->Combine
.SourceRGB
,
474 texUnit
->Combine
.OperandRGB
);
475 out
= emit_combine( p
, dest
, A0_DEST_CHANNEL_W
, saturate
,
477 texUnit
->Combine
.ModeA
,
478 texUnit
->Combine
.SourceA
,
479 texUnit
->Combine
.OperandA
);
482 /* Deal with the final shift:
484 if (alpha_shift
|| rgb_shift
) {
485 if (rgb_shift
== alpha_shift
) {
486 shift
= i915_emit_const1f(p
, 1<<rgb_shift
);
487 shift
= swizzle(shift
,X
,X
,X
,X
);
490 shift
= i915_emit_const2f(p
, 1<<rgb_shift
, 1<<alpha_shift
);
491 shift
= swizzle(shift
,X
,X
,X
,Y
);
493 return i915_emit_arith( p
, A0_MUL
, dest
, A0_DEST_CHANNEL_ALL
,
494 saturate
, out
, shift
, 0 );
501 return get_source(p
, GL_PREVIOUS
, 0);
505 static void emit_program_fini( struct i915_fragment_program
*p
)
507 int cf
= get_source( p
, GL_PREVIOUS
, 0 );
508 int out
= UREG( REG_TYPE_OC
, 0 );
510 if (p
->ctx
->_TriangleCaps
& DD_SEPARATE_SPECULAR
) {
511 /* Emit specular add.
513 GLuint s
= i915_emit_decl(p
, REG_TYPE_T
, T_SPECULAR
, D0_CHANNEL_ALL
);
514 i915_emit_arith( p
, A0_ADD
, out
, A0_DEST_CHANNEL_ALL
, 0, cf
,
515 swizzle(s
, X
,Y
,Z
,ZERO
), 0 );
517 else if (cf
!= out
) {
518 /* Will wind up in here if no texture enabled or a couple of
519 * other scenarios (GL_REPLACE for instance).
521 i915_emit_arith( p
, A0_MOV
, out
, A0_DEST_CHANNEL_ALL
, 0, cf
, 0, 0 );
526 static void i915EmitTextureProgram( i915ContextPtr i915
)
528 GLcontext
*ctx
= &i915
->intel
.ctx
;
529 struct i915_fragment_program
*p
= &i915
->tex_program
;
532 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
534 i915_init_program( i915
, p
);
536 if (ctx
->Texture
._EnabledUnits
) {
537 for (unit
= 0 ; unit
< ctx
->Const
.MaxTextureUnits
; unit
++)
538 if (ctx
->Texture
.Unit
[unit
]._ReallyEnabled
) {
539 p
->last_tex_stage
= unit
;
542 for (unit
= 0 ; unit
< ctx
->Const
.MaxTextureUnits
; unit
++)
543 if (ctx
->Texture
.Unit
[unit
]._ReallyEnabled
) {
544 p
->src_previous
= emit_texenv( p
, unit
);
545 p
->src_texture
= UREG_BAD
;
546 p
->temp_flag
= 0xffff000;
547 p
->temp_flag
|= 1 << GET_UREG_NR(p
->src_previous
);
551 emit_program_fini( p
);
553 i915_fini_program( p
);
554 i915_upload_program( i915
, p
);
560 void i915ValidateTextureProgram( i915ContextPtr i915
)
562 intelContextPtr intel
= &i915
->intel
;
563 GLcontext
*ctx
= &intel
->ctx
;
564 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
565 struct vertex_buffer
*VB
= &tnl
->vb
;
566 GLuint index
= tnl
->render_inputs
;
568 GLuint s4
= i915
->state
.Ctx
[I915_CTXREG_LIS4
] & ~S4_VFMT_MASK
;
569 GLuint s2
= S2_TEXCOORD_NONE
;
573 VB
->AttribPtr
[VERT_ATTRIB_POS
] = VB
->NdcPtr
;
574 intel
->vertex_attr_count
= 0;
575 intel
->coloroffset
= 0;
576 intel
->specoffset
= 0;
579 if (i915
->vertex_fog
== I915_FOG_PIXEL
) {
580 EMIT_ATTR( _TNL_ATTRIB_POS
, EMIT_4F_VIEWPORT
, S4_VFMT_XYZW
, 16 );
581 index
&= ~_TNL_BIT_FOG
;
583 else if (index
& _TNL_BITS_TEX_ANY
) {
584 EMIT_ATTR( _TNL_ATTRIB_POS
, EMIT_4F_VIEWPORT
, S4_VFMT_XYZW
, 16 );
587 EMIT_ATTR( _TNL_ATTRIB_POS
, EMIT_3F_VIEWPORT
, S4_VFMT_XYZ
, 12 );
590 /* How undefined is undefined? */
591 if (index
& _TNL_BIT_POINTSIZE
) {
592 EMIT_ATTR( _TNL_ATTRIB_POINTSIZE
, EMIT_1F
, S4_VFMT_POINT_WIDTH
, 4 );
595 intel
->coloroffset
= offset
/ 4;
596 EMIT_ATTR( _TNL_ATTRIB_COLOR0
, EMIT_4UB_4F_BGRA
, S4_VFMT_COLOR
, 4 );
598 if (index
& (_TNL_BIT_COLOR1
|_TNL_BIT_FOG
)) {
599 if (index
& _TNL_BIT_COLOR1
) {
600 intel
->specoffset
= offset
/ 4;
601 EMIT_ATTR( _TNL_ATTRIB_COLOR1
, EMIT_3UB_3F_BGR
, S4_VFMT_SPEC_FOG
, 3 );
605 if (index
& _TNL_BIT_FOG
)
606 EMIT_ATTR( _TNL_ATTRIB_FOG
, EMIT_1UB_1F
, S4_VFMT_SPEC_FOG
, 1 );
611 if (index
& _TNL_BITS_TEX_ANY
) {
612 for (i
= 0; i
< 8; i
++) {
613 if (index
& _TNL_BIT_TEX(i
)) {
614 int sz
= VB
->TexCoordPtr
[i
]->size
;
616 s2
&= ~S2_TEXCOORD_FMT(i
, S2_TEXCOORD_FMT0_MASK
);
617 s2
|= S2_TEXCOORD_FMT(i
, SZ_TO_HW(sz
));
619 EMIT_ATTR( _TNL_ATTRIB_TEX0
+i
, EMIT_SZ(sz
), 0, sz
* 4 );
624 /* Only need to change the vertex emit code if there has been a
625 * statechange to a new hardware vertex format:
627 if (s2
!= i915
->state
.Ctx
[I915_CTXREG_LIS2
] ||
628 s4
!= i915
->state
.Ctx
[I915_CTXREG_LIS4
]) {
630 I915_STATECHANGE( i915
, I915_UPLOAD_CTX
);
632 i915
->tex_program
.translated
= 0;
634 /* Must do this *after* statechange, so as not to affect
635 * buffered vertices reliant on the old state:
637 intel
->vertex_size
= _tnl_install_attrs( ctx
,
639 intel
->vertex_attr_count
,
640 intel
->ViewportMatrix
.m
, 0 );
642 intel
->vertex_size
>>= 2;
644 i915
->state
.Ctx
[I915_CTXREG_LIS2
] = s2
;
645 i915
->state
.Ctx
[I915_CTXREG_LIS4
] = s4
;
647 assert(intel
->vtbl
.check_vertex_size( intel
, intel
->vertex_size
));
650 if (!i915
->tex_program
.translated
||
651 i915
->last_ReallyEnabled
!= ctx
->Texture
._EnabledUnits
) {
652 i915EmitTextureProgram( i915
);
653 i915
->last_ReallyEnabled
= ctx
->Texture
._EnabledUnits
;