|
|
|
@@ -1,777 +0,0 @@ |
|
|
|
/* |
|
|
|
* Mesa 3-D graphics library |
|
|
|
* Version: 6.5 |
|
|
|
* |
|
|
|
* Copyright (C) 1999-2005 Brian Paul All Rights Reserved. |
|
|
|
* |
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a |
|
|
|
* copy of this software and associated documentation files (the "Software"), |
|
|
|
* to deal in the Software without restriction, including without limitation |
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the |
|
|
|
* Software is furnished to do so, subject to the following conditions: |
|
|
|
* |
|
|
|
* The above copyright notice and this permission notice shall be included |
|
|
|
* in all copies or substantial portions of the Software. |
|
|
|
* |
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
|
|
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
|
|
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
|
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
*/ |
|
|
|
|
|
|
|
/* An amusing little utility to print ARB fragment programs out as a C |
|
|
|
* function. Resulting code not tested except visually. |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
#include "glheader.h" |
|
|
|
#include "colormac.h" |
|
|
|
#include "context.h" |
|
|
|
#include "program_instruction.h" |
|
|
|
#include "macros.h" |
|
|
|
#include "program.h" |
|
|
|
|
|
|
|
#include "s_nvfragprog.h" |
|
|
|
#include "s_span.h" |
|
|
|
|
|
|
|
|
|
|
|
#ifdef USE_TCC |
|
|
|
|
|
|
|
/* UREG - a way of representing an FP source register including |
|
|
|
* swizzling and negation in a single GLuint. Major flaw is the |
|
|
|
* limitiation to source->Index < 32. Secondary flaw is the fact that |
|
|
|
* it's overkill & we could probably just pass around the original |
|
|
|
* datatypes instead. |
|
|
|
*/ |
|
|
|
|
|
|
|
#define UREG_TYPE_TEMP 0 |
|
|
|
#define UREG_TYPE_INTERP 1 |
|
|
|
#define UREG_TYPE_LOCAL_CONST 2 |
|
|
|
#define UREG_TYPE_ENV_CONST 3 |
|
|
|
#define UREG_TYPE_STATE_CONST 4 |
|
|
|
#define UREG_TYPE_PARAM 5 |
|
|
|
#define UREG_TYPE_OUTPUT 6 |
|
|
|
#define UREG_TYPE_MASK 0x7 |
|
|
|
|
|
|
|
#define UREG_TYPE_SHIFT 29 |
|
|
|
#define UREG_NR_SHIFT 24 |
|
|
|
#define UREG_NR_MASK 0x1f /* 31 */ |
|
|
|
#define UREG_CHANNEL_X_NEGATE_SHIFT 23 |
|
|
|
#define UREG_CHANNEL_X_SHIFT 20 |
|
|
|
#define UREG_CHANNEL_Y_NEGATE_SHIFT 19 |
|
|
|
#define UREG_CHANNEL_Y_SHIFT 16 |
|
|
|
#define UREG_CHANNEL_Z_NEGATE_SHIFT 15 |
|
|
|
#define UREG_CHANNEL_Z_SHIFT 12 |
|
|
|
#define UREG_CHANNEL_W_NEGATE_SHIFT 11 |
|
|
|
#define UREG_CHANNEL_W_SHIFT 8 |
|
|
|
#define UREG_CHANNEL_ZERO_NEGATE_MBZ 5 |
|
|
|
#define UREG_CHANNEL_ZERO_SHIFT 4 |
|
|
|
#define UREG_CHANNEL_ONE_NEGATE_MBZ 1 |
|
|
|
#define UREG_CHANNEL_ONE_SHIFT 0 |
|
|
|
|
|
|
|
#define UREG_BAD 0xffffffff /* not a valid ureg */ |
|
|
|
|
|
|
|
#define _X 0 |
|
|
|
#define _Y 1 |
|
|
|
#define _Z 2 |
|
|
|
#define _W 3 |
|
|
|
#define _ZERO 4 /* NOTE! */ |
|
|
|
#define _ONE 5 /* NOTE! */ |
|
|
|
|
|
|
|
|
|
|
|
/* Construct a ureg: |
|
|
|
*/ |
|
|
|
#define UREG( type, nr ) (((type)<< UREG_TYPE_SHIFT) | \ |
|
|
|
((nr) << UREG_NR_SHIFT) | \ |
|
|
|
(_X << UREG_CHANNEL_X_SHIFT) | \ |
|
|
|
(_Y << UREG_CHANNEL_Y_SHIFT) | \ |
|
|
|
(_Z << UREG_CHANNEL_Z_SHIFT) | \ |
|
|
|
(_W << UREG_CHANNEL_W_SHIFT) | \ |
|
|
|
(_ZERO << UREG_CHANNEL_ZERO_SHIFT) | \ |
|
|
|
(_ONE << UREG_CHANNEL_ONE_SHIFT)) |
|
|
|
|
|
|
|
#define GET_CHANNEL_SRC( reg, channel ) ((reg<<(channel*4)) & \ |
|
|
|
(0xf<<UREG_CHANNEL_X_SHIFT)) |
|
|
|
#define CHANNEL_SRC( src, channel ) (src>>(channel*4)) |
|
|
|
|
|
|
|
#define GET_UREG_TYPE(reg) (((reg)>>UREG_TYPE_SHIFT)&UREG_TYPE_MASK) |
|
|
|
#define GET_UREG_NR(reg) (((reg)>>UREG_NR_SHIFT)&UREG_NR_MASK) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define UREG_XYZW_CHANNEL_MASK 0x00ffff00 |
|
|
|
|
|
|
|
#define deref(reg,pos) swizzle(reg, pos, pos, pos, pos) |
|
|
|
|
|
|
|
|
|
|
|
static INLINE int is_swizzled( int reg ) |
|
|
|
{ |
|
|
|
return ((reg & UREG_XYZW_CHANNEL_MASK) != |
|
|
|
(UREG(0,0) & UREG_XYZW_CHANNEL_MASK)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* One neat thing about the UREG representation: |
|
|
|
*/ |
|
|
|
static INLINE int swizzle( int reg, int x, int y, int z, int w ) |
|
|
|
{ |
|
|
|
return ((reg & ~UREG_XYZW_CHANNEL_MASK) | |
|
|
|
CHANNEL_SRC( GET_CHANNEL_SRC( reg, x ), 0 ) | |
|
|
|
CHANNEL_SRC( GET_CHANNEL_SRC( reg, y ), 1 ) | |
|
|
|
CHANNEL_SRC( GET_CHANNEL_SRC( reg, z ), 2 ) | |
|
|
|
CHANNEL_SRC( GET_CHANNEL_SRC( reg, w ), 3 )); |
|
|
|
} |
|
|
|
|
|
|
|
/* Another neat thing about the UREG representation: |
|
|
|
*/ |
|
|
|
static INLINE int negate( int reg, int x, int y, int z, int w ) |
|
|
|
{ |
|
|
|
return reg ^ (((x&1)<<UREG_CHANNEL_X_NEGATE_SHIFT)| |
|
|
|
((y&1)<<UREG_CHANNEL_Y_NEGATE_SHIFT)| |
|
|
|
((z&1)<<UREG_CHANNEL_Z_NEGATE_SHIFT)| |
|
|
|
((w&1)<<UREG_CHANNEL_W_NEGATE_SHIFT)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static GLuint src_reg_file( GLuint file ) |
|
|
|
{ |
|
|
|
switch (file) { |
|
|
|
case PROGRAM_TEMPORARY: return UREG_TYPE_TEMP; |
|
|
|
case PROGRAM_INPUT: return UREG_TYPE_INTERP; |
|
|
|
case PROGRAM_LOCAL_PARAM: return UREG_TYPE_LOCAL_CONST; |
|
|
|
case PROGRAM_ENV_PARAM: return UREG_TYPE_ENV_CONST; |
|
|
|
|
|
|
|
case PROGRAM_STATE_VAR: return UREG_TYPE_STATE_CONST; |
|
|
|
case PROGRAM_NAMED_PARAM: return UREG_TYPE_PARAM; |
|
|
|
default: return UREG_BAD; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void emit( struct fragment_program *p, |
|
|
|
const char *fmt, |
|
|
|
... ) |
|
|
|
{ |
|
|
|
va_list ap; |
|
|
|
va_start( ap, fmt ); |
|
|
|
|
|
|
|
if (p->c_strlen < sizeof(p->c_str)) |
|
|
|
p->c_strlen += vsnprintf( p->c_str + p->c_strlen, |
|
|
|
sizeof(p->c_str) - p->c_strlen, |
|
|
|
fmt, ap ); |
|
|
|
|
|
|
|
va_end( ap ); |
|
|
|
} |
|
|
|
|
|
|
|
static INLINE void emit_char( struct fragment_program *p, char c ) |
|
|
|
{ |
|
|
|
if (p->c_strlen < sizeof(p->c_str)) { |
|
|
|
p->c_str[p->c_strlen] = c; |
|
|
|
p->c_strlen++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Retrieve a ureg for the given source register. Will emit |
|
|
|
* constants, apply swizzling and negation as needed. |
|
|
|
*/ |
|
|
|
static GLuint src_vector( const struct prog_src_register *source ) |
|
|
|
{ |
|
|
|
GLuint src; |
|
|
|
|
|
|
|
assert(source->Index < 32); /* limitiation of UREG representation */ |
|
|
|
|
|
|
|
src = UREG( src_reg_file( source->File ), source->Index ); |
|
|
|
|
|
|
|
src = swizzle(src, |
|
|
|
_X + source->Swizzle[0], |
|
|
|
_X + source->Swizzle[1], |
|
|
|
_X + source->Swizzle[2], |
|
|
|
_X + source->Swizzle[3]); |
|
|
|
|
|
|
|
if (source->NegateBase) |
|
|
|
src = negate( src, 1,1,1,1 ); |
|
|
|
|
|
|
|
return src; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void print_header( struct fragment_program *p ) |
|
|
|
{ |
|
|
|
emit(p, "\n\n\n"); |
|
|
|
|
|
|
|
/* Mesa's program_parameter struct: |
|
|
|
*/ |
|
|
|
emit(p, |
|
|
|
"struct program_parameter\n" |
|
|
|
"{\n" |
|
|
|
" const char *Name;\n" |
|
|
|
" int Type;\n" |
|
|
|
" int StateIndexes[6];\n" |
|
|
|
" float Values[4];\n" |
|
|
|
"};\n"); |
|
|
|
|
|
|
|
|
|
|
|
/* Texture samplers, not written yet: |
|
|
|
*/ |
|
|
|
emit(p, "extern void TEX( void *ctx, const float *txc, int unit, float *rslt );\n" |
|
|
|
"extern void TXB( void *ctx, const float *txc, int unit, float *rslt );\n" |
|
|
|
"extern void TXP( void *ctx, const float *txc, int unit, float *rslt );\n"); |
|
|
|
|
|
|
|
/* Resort to the standard math library (float versions): |
|
|
|
*/ |
|
|
|
emit(p, "extern float fabsf( float );\n" |
|
|
|
"extern float cosf( float );\n" |
|
|
|
"extern float sinf( float );\n" |
|
|
|
"extern float expf( float );\n" |
|
|
|
"extern float powf( float, float );\n" |
|
|
|
"extern float floorf( float );\n"); |
|
|
|
|
|
|
|
/* These ones we have fast code in Mesa for: |
|
|
|
*/ |
|
|
|
emit(p, "extern float LOG2( float );\n" |
|
|
|
"extern float _mesa_inv_sqrtf( float );\n"); |
|
|
|
|
|
|
|
/* The usual macros, not really needed, but handy: |
|
|
|
*/ |
|
|
|
emit(p, "#define MIN2(x,y) ((x)<(y)?(x):(y))\n" |
|
|
|
"#define MAX2(x,y) ((x)<(y)?(x):(y))\n" |
|
|
|
"#define SATURATE(x) ((x)>1.0?1.0:((x)<0.0?0.0:(x)))\n"); |
|
|
|
|
|
|
|
/* Our function! |
|
|
|
*/ |
|
|
|
emit(p, "int run_program( void *ctx, \n" |
|
|
|
" const float (*local_param)[4], \n" |
|
|
|
" const float (*env_param)[4], \n" |
|
|
|
" const struct program_parameter *state_param, \n" |
|
|
|
" const float (*interp)[4], \n" |
|
|
|
" float (*outputs)[4])\n" |
|
|
|
"{\n" |
|
|
|
" float temp[32][4];\n" |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
static void print_footer( struct fragment_program *p ) |
|
|
|
{ |
|
|
|
emit(p, " return 1;"); |
|
|
|
emit(p, "}\n"); |
|
|
|
} |
|
|
|
|
|
|
|
static void print_dest_reg( struct fragment_program *p, |
|
|
|
const struct prog_instruction *inst ) |
|
|
|
{ |
|
|
|
switch (inst->DstReg.File) { |
|
|
|
case PROGRAM_OUTPUT: |
|
|
|
emit(p, "outputs[%d]", inst->DstReg.Index); |
|
|
|
break; |
|
|
|
case PROGRAM_TEMPORARY: |
|
|
|
emit(p, "temp[%d]", inst->DstReg.Index); |
|
|
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void print_dest( struct fragment_program *p, |
|
|
|
const struct prog_instruction *inst, |
|
|
|
GLuint idx ) |
|
|
|
{ |
|
|
|
print_dest_reg(p, inst); |
|
|
|
emit(p, "[%d]", idx); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#define UREG_SRC0(reg) (((reg)>>UREG_CHANNEL_X_SHIFT) & 0x7) |
|
|
|
|
|
|
|
static void print_reg( struct fragment_program *p, |
|
|
|
GLuint arg ) |
|
|
|
{ |
|
|
|
switch (GET_UREG_TYPE(arg)) { |
|
|
|
case UREG_TYPE_TEMP: emit(p, "temp"); break; |
|
|
|
case UREG_TYPE_INTERP: emit(p, "interp"); break; |
|
|
|
case UREG_TYPE_LOCAL_CONST: emit(p, "local_const"); break; |
|
|
|
case UREG_TYPE_ENV_CONST: emit(p, "env_const"); break; |
|
|
|
case UREG_TYPE_STATE_CONST: emit(p, "state_param"); break; |
|
|
|
case UREG_TYPE_PARAM: emit(p, "local_param"); break; |
|
|
|
}; |
|
|
|
|
|
|
|
emit(p, "[%d]", GET_UREG_NR(arg)); |
|
|
|
|
|
|
|
if (GET_UREG_TYPE(arg) == UREG_TYPE_STATE_CONST) { |
|
|
|
emit(p, ".Values"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void print_arg( struct fragment_program *p, |
|
|
|
GLuint arg ) |
|
|
|
{ |
|
|
|
GLuint src = UREG_SRC0(arg); |
|
|
|
|
|
|
|
if (src == _ZERO) { |
|
|
|
emit(p, "0"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (arg & (1<<UREG_CHANNEL_X_NEGATE_SHIFT)) |
|
|
|
emit(p, "-"); |
|
|
|
|
|
|
|
if (src == _ONE) { |
|
|
|
emit(p, "1"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (GET_UREG_TYPE(arg) == UREG_TYPE_STATE_CONST && |
|
|
|
p->Parameters->Parameters[GET_UREG_NR(arg)].Type == CONSTANT) { |
|
|
|
emit(p, "%g", p->Parameters->Parameters[GET_UREG_NR(arg)].Values[src]); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
print_reg( p, arg ); |
|
|
|
|
|
|
|
switch (src){ |
|
|
|
case _X: emit(p, "[0]"); break; |
|
|
|
case _Y: emit(p, "[1]"); break; |
|
|
|
case _Z: emit(p, "[2]"); break; |
|
|
|
case _W: emit(p, "[3]"); break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* This is where the handling of expressions breaks down into string |
|
|
|
* processing: |
|
|
|
*/ |
|
|
|
static void print_expression( struct fragment_program *p, |
|
|
|
GLuint i, |
|
|
|
const char *fmt, |
|
|
|
va_list ap ) |
|
|
|
{ |
|
|
|
while (*fmt) { |
|
|
|
if (*fmt == '%' && *(fmt+1) == 's') { |
|
|
|
int reg = va_arg(ap, int); |
|
|
|
|
|
|
|
/* Use of deref() is a bit of a hack: |
|
|
|
*/ |
|
|
|
print_arg( p, deref(reg, i) ); |
|
|
|
fmt += 2; |
|
|
|
} |
|
|
|
else { |
|
|
|
emit_char(p, *fmt); |
|
|
|
fmt++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
emit(p, ";\n"); |
|
|
|
} |
|
|
|
|
|
|
|
static void do_tex_kill( struct fragment_program *p, |
|
|
|
const struct prog_instruction *inst, |
|
|
|
GLuint arg ) |
|
|
|
{ |
|
|
|
GLuint i; |
|
|
|
|
|
|
|
emit(p, "if ("); |
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) { |
|
|
|
print_arg( p, deref(arg, i) ); |
|
|
|
emit(p, " < 0 "); |
|
|
|
if (i + 1 < 4) |
|
|
|
emit(p, "|| "); |
|
|
|
} |
|
|
|
|
|
|
|
emit(p, ")\n"); |
|
|
|
emit(p, " return 0;\n"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
static void do_tex_simple( struct fragment_program *p, |
|
|
|
const struct prog_instruction *inst, |
|
|
|
const char *fn, GLuint texunit, GLuint arg ) |
|
|
|
{ |
|
|
|
emit(p, " %s( ctx, ", fn); |
|
|
|
print_reg( p, arg ); |
|
|
|
emit(p, ", %d, ", texunit ); |
|
|
|
print_dest_reg(p, inst); |
|
|
|
emit(p, ");\n"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void do_tex( struct fragment_program *p, |
|
|
|
const struct prog_instruction *inst, |
|
|
|
const char *fn, GLuint texunit, GLuint arg ) |
|
|
|
{ |
|
|
|
GLuint i; |
|
|
|
GLboolean need_tex = GL_FALSE, need_result = GL_FALSE; |
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) |
|
|
|
if (!inst->DstReg.WriteMask[i]) |
|
|
|
need_result = GL_TRUE; |
|
|
|
|
|
|
|
if (is_swizzled(arg)) |
|
|
|
need_tex = GL_TRUE; |
|
|
|
|
|
|
|
if (!need_tex && !need_result) { |
|
|
|
do_tex_simple( p, inst, fn, texunit, arg ); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
emit(p, " {\n"); |
|
|
|
emit(p, " float texcoord[4];\n"); |
|
|
|
emit(p, " float result[4];\n"); |
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) { |
|
|
|
emit(p, " texcoord[%d] = ", i); |
|
|
|
print_arg( p, deref(arg, i) ); |
|
|
|
emit(p, ";\n"); |
|
|
|
} |
|
|
|
|
|
|
|
emit(p, " %s( ctx, texcoord, %d, result);\n", fn, texunit ); |
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) { |
|
|
|
if (inst->DstReg.WriteMask[i]) { |
|
|
|
emit(p, " "); |
|
|
|
print_dest(p, inst, i); |
|
|
|
emit(p, " = result[%d];\n", i); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
emit(p, " }\n"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void saturate( struct fragment_program *p, |
|
|
|
const struct prog_instruction *inst, |
|
|
|
GLuint i ) |
|
|
|
{ |
|
|
|
emit(p, " "); |
|
|
|
print_dest(p, inst, i); |
|
|
|
emit(p, " = SATURATE( "); |
|
|
|
print_dest(p, inst, i); |
|
|
|
emit(p, ");\n"); |
|
|
|
} |
|
|
|
|
|
|
|
static void assign_single( GLuint i, |
|
|
|
struct fragment_program *p, |
|
|
|
const struct prog_instruction *inst, |
|
|
|
const char *fmt, |
|
|
|
... ) |
|
|
|
{ |
|
|
|
va_list ap; |
|
|
|
va_start( ap, fmt ); |
|
|
|
|
|
|
|
if (inst->DstReg.WriteMask[i]) { |
|
|
|
emit(p, " "); |
|
|
|
print_dest(p, inst, i); |
|
|
|
emit(p, " = "); |
|
|
|
print_expression( p, i, fmt, ap); |
|
|
|
if (inst->Saturate) |
|
|
|
saturate(p, inst, i); |
|
|
|
} |
|
|
|
|
|
|
|
va_end( ap ); |
|
|
|
} |
|
|
|
|
|
|
|
static void assign4( struct fragment_program *p, |
|
|
|
const struct prog_instruction *inst, |
|
|
|
const char *fmt, |
|
|
|
... ) |
|
|
|
{ |
|
|
|
GLuint i; |
|
|
|
va_list ap; |
|
|
|
va_start( ap, fmt ); |
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) |
|
|
|
if (inst->DstReg.WriteMask[i]) { |
|
|
|
emit(p, " "); |
|
|
|
print_dest(p, inst, i); |
|
|
|
emit(p, " = "); |
|
|
|
print_expression( p, i, fmt, ap); |
|
|
|
if (inst->Saturate) |
|
|
|
saturate(p, inst, i); |
|
|
|
} |
|
|
|
|
|
|
|
va_end( ap ); |
|
|
|
} |
|
|
|
|
|
|
|
static void assign4_replicate( struct fragment_program *p, |
|
|
|
const struct prog_instruction *inst, |
|
|
|
const char *fmt, |
|
|
|
... ) |
|
|
|
{ |
|
|
|
GLuint i, first = 0; |
|
|
|
GLboolean ok = 0; |
|
|
|
va_list ap; |
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) |
|
|
|
if (inst->DstReg.WriteMask[i]) { |
|
|
|
ok = 1; |
|
|
|
first = i; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if (!ok) return; |
|
|
|
|
|
|
|
va_start( ap, fmt ); |
|
|
|
|
|
|
|
emit(p, " "); |
|
|
|
|
|
|
|
print_dest(p, inst, first); |
|
|
|
emit(p, " = "); |
|
|
|
print_expression( p, 0, fmt, ap); |
|
|
|
if (inst->Saturate) |
|
|
|
saturate(p, inst, first); |
|
|
|
va_end( ap ); |
|
|
|
|
|
|
|
for (i = first+1; i < 4; i++) |
|
|
|
if (inst->DstReg.WriteMask[i]) { |
|
|
|
emit(p, " "); |
|
|
|
print_dest(p, inst, i); |
|
|
|
emit(p, " = "); |
|
|
|
print_dest(p, inst, first); |
|
|
|
emit(p, ";\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void translate_program( struct fragment_program *p ) |
|
|
|
{ |
|
|
|
const struct prog_instruction *inst = p->Instructions; |
|
|
|
|
|
|
|
for (; inst->Opcode != OPCODE_END; inst++) { |
|
|
|
|
|
|
|
GLuint src[3], i; |
|
|
|
GLuint nr = _mesa_num_inst_src_regs( inst->Opcode ); |
|
|
|
|
|
|
|
for (i = 0; i < nr; i++) |
|
|
|
src[i] = src_vector( &inst->SrcReg[i] ); |
|
|
|
|
|
|
|
/* Print the original program instruction string */ |
|
|
|
if (p->Base.String) |
|
|
|
{ |
|
|
|
const char *s = (const char *) p->Base.String + inst->StringPos; |
|
|
|
emit(p, " /* "); |
|
|
|
while (*s != ';') { |
|
|
|
emit_char(p, *s); |
|
|
|
s++; |
|
|
|
} |
|
|
|
emit(p, "; */\n"); |
|
|
|
} |
|
|
|
|
|
|
|
switch (inst->Opcode) { |
|
|
|
case OPCODE_ABS: |
|
|
|
assign4(p, inst, "fabsf(%s)", src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_ADD: |
|
|
|
assign4(p, inst, "%s + %s", src[0], src[1]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_CMP: |
|
|
|
assign4(p, inst, "%s < 0.0F ? %s : %s", src[0], src[1], src[2]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_COS: |
|
|
|
assign4_replicate(p, inst, "COS(%s)", src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_DP3: |
|
|
|
assign4_replicate(p, inst, |
|
|
|
"%s*%s + %s*%s + %s*%s", |
|
|
|
deref(src[0],_X), |
|
|
|
deref(src[1],_X), |
|
|
|
deref(src[0],_Y), |
|
|
|
deref(src[1],_Y), |
|
|
|
deref(src[0],_Z), |
|
|
|
deref(src[1],_Z)); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_DP4: |
|
|
|
assign4_replicate(p, inst, |
|
|
|
"%s*%s + %s*%s + %s*%s + %s*%s", |
|
|
|
deref(src[0],_X), |
|
|
|
deref(src[1],_X), |
|
|
|
deref(src[0],_Y), |
|
|
|
deref(src[1],_Y), |
|
|
|
deref(src[0],_Z), |
|
|
|
deref(src[1],_Z)); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_DPH: |
|
|
|
assign4_replicate(p, inst, |
|
|
|
"%s*%s + %s*%s + %s*%s + %s", |
|
|
|
deref(src[0],_X), |
|
|
|
deref(src[1],_X), |
|
|
|
deref(src[0],_Y), |
|
|
|
deref(src[1],_Y), |
|
|
|
deref(src[1],_Z)); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_DST: |
|
|
|
/* result[0] = 1 * 1; |
|
|
|
* result[1] = a[1] * b[1]; |
|
|
|
* result[2] = a[2] * 1; |
|
|
|
* result[3] = 1 * b[3]; |
|
|
|
*/ |
|
|
|
assign_single(0, p, inst, "1.0"); |
|
|
|
|
|
|
|
assign_single(1, p, inst, "%s * %s", |
|
|
|
deref(src[0], _Y), deref(src[1], _Y)); |
|
|
|
|
|
|
|
assign_single(2, p, inst, "%s", deref(src[0], _Z)); |
|
|
|
assign_single(3, p, inst, "%s", deref(src[1], _W)); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_EX2: |
|
|
|
assign4_replicate(p, inst, "powf(2.0, %s)", src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_FLR: |
|
|
|
assign4_replicate(p, inst, "floorf(%s)", src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_FRC: |
|
|
|
assign4_replicate(p, inst, "%s - floorf(%s)", src[0], src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_KIL: |
|
|
|
do_tex_kill(p, inst, src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_LG2: |
|
|
|
assign4_replicate(p, inst, "LOG2(%s)", src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_LIT: |
|
|
|
assign_single(0, p, inst, "1.0"); |
|
|
|
assign_single(1, p, inst, "MIN2(%s, 0)", deref(src[0], _X)); |
|
|
|
assign_single(2, p, inst, "(%s > 0.0) ? expf(%s * MIN2(%s, 0)) : 0.0", |
|
|
|
deref(src[0], _X), |
|
|
|
deref(src[0], _Z), |
|
|
|
deref(src[0], _Y)); |
|
|
|
assign_single(3, p, inst, "1.0"); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_LRP: |
|
|
|
assign4(p, inst, |
|
|
|
"%s * %s + (1.0 - %s) * %s", |
|
|
|
src[0], src[1], src[0], src[2]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_MAD: |
|
|
|
assign4(p, inst, "%s * %s + %s", src[0], src[1], src[2]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_MAX: |
|
|
|
assign4(p, inst, "MAX2(%s, %s)", src[0], src[1]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_MIN: |
|
|
|
assign4(p, inst, "MIN2(%s, %s)", src[0], src[1]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_MOV: |
|
|
|
assign4(p, inst, "%s", src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_MUL: |
|
|
|
assign4(p, inst, "%s * %s", src[0], src[1]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_POW: |
|
|
|
assign4_replicate(p, inst, "powf(%s, %s)", src[0], src[1]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_RCP: |
|
|
|
assign4_replicate(p, inst, "1.0/%s", src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_RSQ: |
|
|
|
assign4_replicate(p, inst, "_mesa_inv_sqrtf(%s)", src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_SCS: |
|
|
|
if (inst->DstReg.WriteMask[0]) { |
|
|
|
assign_single(0, p, inst, "cosf(%s)", deref(src[0], _X)); |
|
|
|
} |
|
|
|
|
|
|
|
if (inst->DstReg.WriteMask[1]) { |
|
|
|
assign_single(1, p, inst, "sinf(%s)", deref(src[0], _X)); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_SGE: |
|
|
|
assign4(p, inst, "%s >= %s ? 1.0 : 0.0", src[0], src[1]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_SIN: |
|
|
|
assign4_replicate(p, inst, "sinf(%s)", src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_SLT: |
|
|
|
assign4(p, inst, "%s < %s ? 1.0 : 0.0", src[0], src[1]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_SUB: |
|
|
|
assign4(p, inst, "%s - %s", src[0], src[1]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_SWZ: /* same implementation as MOV: */ |
|
|
|
assign4(p, inst, "%s", src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_TEX: |
|
|
|
do_tex(p, inst, "TEX", inst->TexSrcUnit, src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_TXB: |
|
|
|
do_tex(p, inst, "TXB", inst->TexSrcUnit, src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_TXP: |
|
|
|
do_tex(p, inst, "TXP", inst->TexSrcUnit, src[0]); |
|
|
|
break; |
|
|
|
|
|
|
|
case OPCODE_XPD: |
|
|
|
/* Cross product: |
|
|
|
* result.x = src[0].y * src[1].z - src[0].z * src[1].y; |
|
|
|
* result.y = src[0].z * src[1].x - src[0].x * src[1].z; |
|
|
|
* result.z = src[0].x * src[1].y - src[0].y * src[1].x; |
|
|
|
* result.w = undef; |
|
|
|
*/ |
|
|
|
assign4(p, inst, |
|
|
|
"%s * %s - %s * %s", |
|
|
|
swizzle(src[0], _Y, _Z, _X, _ONE), |
|
|
|
swizzle(src[1], _Z, _X, _Y, _ONE), |
|
|
|
swizzle(src[0], _Z, _X, _Y, _ONE), |
|
|
|
swizzle(src[1], _Y, _Z, _X, _ONE)); |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
emit(p, "BOGUS OPCODE\n"); |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void _swrast_translate_program( GLcontext *ctx ) |
|
|
|
{ |
|
|
|
struct fragment_program *p = ctx->FragmentProgram._Current; |
|
|
|
|
|
|
|
if (p) { |
|
|
|
p->c_strlen = 0; |
|
|
|
|
|
|
|
print_header( p ); |
|
|
|
translate_program( p ); |
|
|
|
print_footer( p ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#endif /*USE_TCC*/ |