📄 texenvprogram.c
字号:
/**************************************************************************
*
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
#include "glheader.h"
#include "macros.h"
#include "enums.h"
#include "texenvprogram.h"
#include "shader/program.h"
#include "shader/nvfragprog.h"
#include "shader/arbfragparse.h"
#define DISASSEM (MESA_VERBOSE & VERBOSE_DISASSEM)
struct mode_opt {
unsigned Source:4;
unsigned Operand:3;
};
struct state_key {
GLuint enabled_units;
unsigned separate_specular:1;
unsigned fog_enabled:1;
unsigned fog_mode:2;
struct {
unsigned enabled:1;
unsigned source_index:3;
unsigned ScaleShiftRGB:2;
unsigned ScaleShiftA:2;
unsigned NumArgsRGB:2;
unsigned ModeRGB:4;
struct mode_opt OptRGB[3];
unsigned NumArgsA:2;
unsigned ModeA:4;
struct mode_opt OptA[3];
} unit[8];
};
#define FOG_LINEAR 0
#define FOG_EXP 1
#define FOG_EXP2 2
#define FOG_UNKNOWN 3
static GLuint translate_fog_mode( GLenum mode )
{
switch (mode) {
case GL_LINEAR: return FOG_LINEAR;
case GL_EXP: return FOG_EXP;
case GL_EXP2: return FOG_EXP2;
default: return FOG_UNKNOWN;
}
}
#define OPR_SRC_COLOR 0
#define OPR_ONE_MINUS_SRC_COLOR 1
#define OPR_SRC_ALPHA 2
#define OPR_ONE_MINUS_SRC_ALPHA 3
#define OPR_ZERO 4
#define OPR_ONE 5
#define OPR_UNKNOWN 7
static GLuint translate_operand( GLenum operand )
{
switch (operand) {
case GL_SRC_COLOR: return OPR_SRC_COLOR;
case GL_ONE_MINUS_SRC_COLOR: return OPR_ONE_MINUS_SRC_COLOR;
case GL_SRC_ALPHA: return OPR_SRC_ALPHA;
case GL_ONE_MINUS_SRC_ALPHA: return OPR_ONE_MINUS_SRC_ALPHA;
case GL_ZERO: return OPR_ZERO;
case GL_ONE: return OPR_ONE;
default: return OPR_UNKNOWN;
}
}
#define SRC_TEXTURE 0
#define SRC_TEXTURE0 1
#define SRC_TEXTURE1 2
#define SRC_TEXTURE2 3
#define SRC_TEXTURE3 4
#define SRC_TEXTURE4 5
#define SRC_TEXTURE5 6
#define SRC_TEXTURE6 7
#define SRC_TEXTURE7 8
#define SRC_CONSTANT 9
#define SRC_PRIMARY_COLOR 10
#define SRC_PREVIOUS 11
#define SRC_UNKNOWN 15
static GLuint translate_source( GLenum src )
{
switch (src) {
case GL_TEXTURE: return SRC_TEXTURE;
case GL_TEXTURE0:
case GL_TEXTURE1:
case GL_TEXTURE2:
case GL_TEXTURE3:
case GL_TEXTURE4:
case GL_TEXTURE5:
case GL_TEXTURE6:
case GL_TEXTURE7: return SRC_TEXTURE0 + (src - GL_TEXTURE0);
case GL_CONSTANT: return SRC_CONSTANT;
case GL_PRIMARY_COLOR: return SRC_PRIMARY_COLOR;
case GL_PREVIOUS: return SRC_PREVIOUS;
default: return SRC_UNKNOWN;
}
}
#define MODE_REPLACE 0
#define MODE_MODULATE 1
#define MODE_ADD 2
#define MODE_ADD_SIGNED 3
#define MODE_INTERPOLATE 4
#define MODE_SUBTRACT 5
#define MODE_DOT3_RGB 6
#define MODE_DOT3_RGB_EXT 7
#define MODE_DOT3_RGBA 8
#define MODE_DOT3_RGBA_EXT 9
#define MODE_MODULATE_ADD_ATI 10
#define MODE_MODULATE_SIGNED_ADD_ATI 11
#define MODE_MODULATE_SUBTRACT_ATI 12
#define MODE_UNKNOWN 15
static GLuint translate_mode( GLenum mode )
{
switch (mode) {
case GL_REPLACE: return MODE_REPLACE;
case GL_MODULATE: return MODE_MODULATE;
case GL_ADD: return MODE_ADD;
case GL_ADD_SIGNED: return MODE_ADD_SIGNED;
case GL_INTERPOLATE: return MODE_INTERPOLATE;
case GL_SUBTRACT: return MODE_SUBTRACT;
case GL_DOT3_RGB: return MODE_DOT3_RGB;
case GL_DOT3_RGB_EXT: return MODE_DOT3_RGB_EXT;
case GL_DOT3_RGBA: return MODE_DOT3_RGBA;
case GL_DOT3_RGBA_EXT: return MODE_DOT3_RGBA_EXT;
case GL_MODULATE_ADD_ATI: return MODE_MODULATE_ADD_ATI;
case GL_MODULATE_SIGNED_ADD_ATI: return MODE_MODULATE_SIGNED_ADD_ATI;
case GL_MODULATE_SUBTRACT_ATI: return MODE_MODULATE_SUBTRACT_ATI;
default: return MODE_UNKNOWN;
}
}
#define TEXTURE_UNKNOWN_INDEX 7
static GLuint translate_tex_src_bit( GLuint bit )
{
switch (bit) {
case TEXTURE_1D_BIT: return TEXTURE_1D_INDEX;
case TEXTURE_2D_BIT: return TEXTURE_2D_INDEX;
case TEXTURE_RECT_BIT: return TEXTURE_RECT_INDEX;
case TEXTURE_3D_BIT: return TEXTURE_3D_INDEX;
case TEXTURE_CUBE_BIT: return TEXTURE_CUBE_INDEX;
default: return TEXTURE_UNKNOWN_INDEX;
}
}
static struct state_key *make_state_key( GLcontext *ctx )
{
struct state_key *key = CALLOC_STRUCT(state_key);
GLuint i, j;
for (i=0;i<MAX_TEXTURE_UNITS;i++) {
struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
if (!texUnit->_ReallyEnabled)
continue;
key->unit[i].enabled = 1;
key->enabled_units |= (1<<i);
key->unit[i].source_index =
translate_tex_src_bit(texUnit->_ReallyEnabled);
key->unit[i].NumArgsRGB = texUnit->_CurrentCombine->_NumArgsRGB;
key->unit[i].NumArgsA = texUnit->_CurrentCombine->_NumArgsA;
key->unit[i].ModeRGB =
translate_mode(texUnit->_CurrentCombine->ModeRGB);
key->unit[i].ModeA =
translate_mode(texUnit->_CurrentCombine->ModeA);
key->unit[i].ScaleShiftRGB = texUnit->_CurrentCombine->ScaleShiftRGB;
key->unit[i].ScaleShiftA = texUnit->_CurrentCombine->ScaleShiftRGB;
for (j=0;j<3;j++) {
key->unit[i].OptRGB[j].Operand =
translate_operand(texUnit->_CurrentCombine->OperandRGB[j]);
key->unit[i].OptA[j].Operand =
translate_operand(texUnit->_CurrentCombine->OperandA[j]);
key->unit[i].OptRGB[j].Source =
translate_source(texUnit->_CurrentCombine->SourceRGB[j]);
key->unit[i].OptA[j].Source =
translate_source(texUnit->_CurrentCombine->SourceA[j]);
}
}
if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR)
key->separate_specular = 1;
if (ctx->Fog.Enabled) {
key->fog_enabled = 1;
key->fog_mode = translate_fog_mode(ctx->Fog.Mode);
}
return key;
}
/* Use uregs to represent registers internally, translate to Mesa's
* expected formats on emit.
*
* NOTE: These are passed by value extensively in this file rather
* than as usual by pointer reference. If this disturbs you, try
* remembering they are just 32bits in size.
*
* GCC is smart enough to deal with these dword-sized structures in
* much the same way as if I had defined them as dwords and was using
* macros to access and set the fields. This is much nicer and easier
* to evolve.
*/
struct ureg {
GLuint file:4;
GLuint idx:8;
GLuint negatebase:1;
GLuint abs:1;
GLuint negateabs:1;
GLuint swz:12;
GLuint pad:5;
};
const static struct ureg undef = {
~0,
~0,
0,
0,
0,
0,
0
};
#define X 0
#define Y 1
#define Z 2
#define W 3
/* State used to build the fragment program:
*/
struct texenv_fragment_program {
struct fragment_program *program;
GLcontext *ctx;
struct state_key *state;
GLuint alu_temps; /* Track texture indirections, see spec. */
GLuint temps_output; /* Track texture indirections, see spec. */
GLuint temp_in_use; /* Tracks temporary regs which are in
* use.
*/
GLboolean error;
struct ureg src_texture[MAX_TEXTURE_UNITS];
/* Reg containing each texture unit's sampled texture color,
* else undef.
*/
struct ureg src_previous; /* Reg containing color from previous
* stage. May need to be decl'd.
*/
GLuint last_tex_stage; /* Number of last enabled texture unit */
struct ureg half;
struct ureg one;
struct ureg zero;
};
static struct ureg make_ureg(GLuint file, GLuint idx)
{
struct ureg reg;
reg.file = file;
reg.idx = idx;
reg.negatebase = 0;
reg.abs = 0;
reg.negateabs = 0;
reg.swz = SWIZZLE_NOOP;
reg.pad = 0;
return reg;
}
static struct ureg swizzle( struct ureg reg, int x, int y, int z, int w )
{
reg.swz = MAKE_SWIZZLE4(GET_SWZ(reg.swz, x),
GET_SWZ(reg.swz, y),
GET_SWZ(reg.swz, z),
GET_SWZ(reg.swz, w));
return reg;
}
static struct ureg swizzle1( struct ureg reg, int x )
{
return swizzle(reg, x, x, x, x);
}
static struct ureg negate( struct ureg reg )
{
reg.negatebase ^= 1;
return reg;
}
static GLboolean is_undef( struct ureg reg )
{
return reg.file == 0xf;
}
static struct ureg get_temp( struct texenv_fragment_program *p )
{
int bit;
/* First try and reuse temps which have been used already:
*/
bit = ffs( ~p->temp_in_use & p->alu_temps );
/* Then any unused temporary:
*/
if (!bit)
bit = ffs( ~p->temp_in_use );
if (!bit) {
_mesa_problem(NULL, "%s: out of temporaries\n", __FILE__);
exit(1);
}
p->temp_in_use |= 1<<(bit-1);
return make_ureg(PROGRAM_TEMPORARY, (bit-1));
}
static struct ureg get_tex_temp( struct texenv_fragment_program *p )
{
int bit;
/* First try to find availble temp not previously used (to avoid
* starting a new texture indirection). According to the spec, the
* ~p->temps_output isn't necessary, but will keep it there for
* now:
*/
bit = ffs( ~p->temp_in_use & ~p->alu_temps & ~p->temps_output );
/* Then any unused temporary:
*/
if (!bit)
bit = ffs( ~p->temp_in_use );
if (!bit) {
_mesa_problem(NULL, "%s: out of temporaries\n", __FILE__);
exit(1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -