/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_build.c |
---|
0,0 → 1,1343 |
/************************************************************************** |
* |
* Copyright 2007 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 "util/u_debug.h" |
#include "pipe/p_format.h" |
#include "pipe/p_shader_tokens.h" |
#include "tgsi_build.h" |
#include "tgsi_parse.h" |
/* |
* header |
*/ |
struct tgsi_header |
tgsi_build_header( void ) |
{ |
struct tgsi_header header; |
header.HeaderSize = 1; |
header.BodySize = 0; |
return header; |
} |
static void |
header_headersize_grow( struct tgsi_header *header ) |
{ |
assert( header->HeaderSize < 0xFF ); |
assert( header->BodySize == 0 ); |
header->HeaderSize++; |
} |
static void |
header_bodysize_grow( struct tgsi_header *header ) |
{ |
assert( header->BodySize < 0xFFFFFF ); |
header->BodySize++; |
} |
struct tgsi_processor |
tgsi_build_processor( |
unsigned type, |
struct tgsi_header *header ) |
{ |
struct tgsi_processor processor; |
processor.Processor = type; |
processor.Padding = 0; |
header_headersize_grow( header ); |
return processor; |
} |
/* |
* declaration |
*/ |
static void |
declaration_grow( |
struct tgsi_declaration *declaration, |
struct tgsi_header *header ) |
{ |
assert( declaration->NrTokens < 0xFF ); |
declaration->NrTokens++; |
header_bodysize_grow( header ); |
} |
static struct tgsi_declaration |
tgsi_default_declaration( void ) |
{ |
struct tgsi_declaration declaration; |
declaration.Type = TGSI_TOKEN_TYPE_DECLARATION; |
declaration.NrTokens = 1; |
declaration.File = TGSI_FILE_NULL; |
declaration.UsageMask = TGSI_WRITEMASK_XYZW; |
declaration.Interpolate = 0; |
declaration.Dimension = 0; |
declaration.Semantic = 0; |
declaration.Invariant = 0; |
declaration.Local = 0; |
declaration.Array = 0; |
declaration.Padding = 0; |
return declaration; |
} |
static struct tgsi_declaration |
tgsi_build_declaration( |
unsigned file, |
unsigned usage_mask, |
unsigned interpolate, |
unsigned dimension, |
unsigned semantic, |
unsigned invariant, |
unsigned local, |
struct tgsi_header *header ) |
{ |
struct tgsi_declaration declaration; |
assert( file < TGSI_FILE_COUNT ); |
assert( interpolate < TGSI_INTERPOLATE_COUNT ); |
declaration = tgsi_default_declaration(); |
declaration.File = file; |
declaration.UsageMask = usage_mask; |
declaration.Interpolate = interpolate; |
declaration.Dimension = dimension; |
declaration.Semantic = semantic; |
declaration.Invariant = invariant; |
declaration.Local = local; |
header_bodysize_grow( header ); |
return declaration; |
} |
static struct tgsi_declaration_range |
tgsi_default_declaration_range( void ) |
{ |
struct tgsi_declaration_range dr; |
dr.First = 0; |
dr.Last = 0; |
return dr; |
} |
static struct tgsi_declaration_range |
tgsi_build_declaration_range( |
unsigned first, |
unsigned last, |
struct tgsi_declaration *declaration, |
struct tgsi_header *header ) |
{ |
struct tgsi_declaration_range declaration_range; |
assert( last >= first ); |
assert( last <= 0xFFFF ); |
declaration_range.First = first; |
declaration_range.Last = last; |
declaration_grow( declaration, header ); |
return declaration_range; |
} |
static struct tgsi_declaration_dimension |
tgsi_build_declaration_dimension(unsigned index_2d, |
struct tgsi_declaration *declaration, |
struct tgsi_header *header) |
{ |
struct tgsi_declaration_dimension dd; |
assert(index_2d <= 0xFFFF); |
dd.Index2D = index_2d; |
dd.Padding = 0; |
declaration_grow(declaration, header); |
return dd; |
} |
static struct tgsi_declaration_interp |
tgsi_default_declaration_interp( void ) |
{ |
struct tgsi_declaration_interp di; |
di.Interpolate = TGSI_INTERPOLATE_CONSTANT; |
di.Centroid = 0; |
di.CylindricalWrap = 0; |
di.Padding = 0; |
return di; |
} |
static struct tgsi_declaration_interp |
tgsi_build_declaration_interp(unsigned interpolate, |
unsigned centroid, |
unsigned cylindrical_wrap, |
struct tgsi_declaration *declaration, |
struct tgsi_header *header) |
{ |
struct tgsi_declaration_interp di; |
di.Interpolate = interpolate; |
di.Centroid = centroid; |
di.CylindricalWrap = cylindrical_wrap; |
di.Padding = 0; |
declaration_grow(declaration, header); |
return di; |
} |
static struct tgsi_declaration_semantic |
tgsi_default_declaration_semantic( void ) |
{ |
struct tgsi_declaration_semantic ds; |
ds.Name = TGSI_SEMANTIC_POSITION; |
ds.Index = 0; |
ds.Padding = 0; |
return ds; |
} |
static struct tgsi_declaration_semantic |
tgsi_build_declaration_semantic( |
unsigned semantic_name, |
unsigned semantic_index, |
struct tgsi_declaration *declaration, |
struct tgsi_header *header ) |
{ |
struct tgsi_declaration_semantic ds; |
assert( semantic_name <= TGSI_SEMANTIC_COUNT ); |
assert( semantic_index <= 0xFFFF ); |
ds.Name = semantic_name; |
ds.Index = semantic_index; |
ds.Padding = 0; |
declaration_grow( declaration, header ); |
return ds; |
} |
static struct tgsi_declaration_resource |
tgsi_default_declaration_resource(void) |
{ |
struct tgsi_declaration_resource dr; |
dr.Resource = TGSI_TEXTURE_BUFFER; |
dr.Raw = 0; |
dr.Writable = 0; |
dr.Padding = 0; |
return dr; |
} |
static struct tgsi_declaration_resource |
tgsi_build_declaration_resource(unsigned texture, |
unsigned raw, |
unsigned writable, |
struct tgsi_declaration *declaration, |
struct tgsi_header *header) |
{ |
struct tgsi_declaration_resource dr; |
dr = tgsi_default_declaration_resource(); |
dr.Resource = texture; |
dr.Raw = raw; |
dr.Writable = writable; |
declaration_grow(declaration, header); |
return dr; |
} |
static struct tgsi_declaration_sampler_view |
tgsi_default_declaration_sampler_view(void) |
{ |
struct tgsi_declaration_sampler_view dsv; |
dsv.Resource = TGSI_TEXTURE_BUFFER; |
dsv.ReturnTypeX = PIPE_TYPE_UNORM; |
dsv.ReturnTypeY = PIPE_TYPE_UNORM; |
dsv.ReturnTypeZ = PIPE_TYPE_UNORM; |
dsv.ReturnTypeW = PIPE_TYPE_UNORM; |
return dsv; |
} |
static struct tgsi_declaration_sampler_view |
tgsi_build_declaration_sampler_view(unsigned texture, |
unsigned return_type_x, |
unsigned return_type_y, |
unsigned return_type_z, |
unsigned return_type_w, |
struct tgsi_declaration *declaration, |
struct tgsi_header *header) |
{ |
struct tgsi_declaration_sampler_view dsv; |
dsv = tgsi_default_declaration_sampler_view(); |
dsv.Resource = texture; |
dsv.ReturnTypeX = return_type_x; |
dsv.ReturnTypeY = return_type_y; |
dsv.ReturnTypeZ = return_type_z; |
dsv.ReturnTypeW = return_type_w; |
declaration_grow(declaration, header); |
return dsv; |
} |
static struct tgsi_declaration_array |
tgsi_default_declaration_array( void ) |
{ |
struct tgsi_declaration_array a; |
a.ArrayID = 0; |
a.Padding = 0; |
return a; |
} |
struct tgsi_full_declaration |
tgsi_default_full_declaration( void ) |
{ |
struct tgsi_full_declaration full_declaration; |
full_declaration.Declaration = tgsi_default_declaration(); |
full_declaration.Range = tgsi_default_declaration_range(); |
full_declaration.Semantic = tgsi_default_declaration_semantic(); |
full_declaration.Interp = tgsi_default_declaration_interp(); |
full_declaration.Resource = tgsi_default_declaration_resource(); |
full_declaration.SamplerView = tgsi_default_declaration_sampler_view(); |
full_declaration.Array = tgsi_default_declaration_array(); |
return full_declaration; |
} |
unsigned |
tgsi_build_full_declaration( |
const struct tgsi_full_declaration *full_decl, |
struct tgsi_token *tokens, |
struct tgsi_header *header, |
unsigned maxsize ) |
{ |
unsigned size = 0; |
struct tgsi_declaration *declaration; |
struct tgsi_declaration_range *dr; |
if( maxsize <= size ) |
return 0; |
declaration = (struct tgsi_declaration *) &tokens[size]; |
size++; |
*declaration = tgsi_build_declaration( |
full_decl->Declaration.File, |
full_decl->Declaration.UsageMask, |
full_decl->Declaration.Interpolate, |
full_decl->Declaration.Dimension, |
full_decl->Declaration.Semantic, |
full_decl->Declaration.Invariant, |
full_decl->Declaration.Local, |
header ); |
if (maxsize <= size) |
return 0; |
dr = (struct tgsi_declaration_range *) &tokens[size]; |
size++; |
*dr = tgsi_build_declaration_range( |
full_decl->Range.First, |
full_decl->Range.Last, |
declaration, |
header ); |
if (full_decl->Declaration.Dimension) { |
struct tgsi_declaration_dimension *dd; |
if (maxsize <= size) { |
return 0; |
} |
dd = (struct tgsi_declaration_dimension *)&tokens[size]; |
size++; |
*dd = tgsi_build_declaration_dimension(full_decl->Dim.Index2D, |
declaration, |
header); |
} |
if (full_decl->Declaration.Interpolate) { |
struct tgsi_declaration_interp *di; |
if (maxsize <= size) { |
return 0; |
} |
di = (struct tgsi_declaration_interp *)&tokens[size]; |
size++; |
*di = tgsi_build_declaration_interp(full_decl->Interp.Interpolate, |
full_decl->Interp.Centroid, |
full_decl->Interp.CylindricalWrap, |
declaration, |
header); |
} |
if( full_decl->Declaration.Semantic ) { |
struct tgsi_declaration_semantic *ds; |
if( maxsize <= size ) |
return 0; |
ds = (struct tgsi_declaration_semantic *) &tokens[size]; |
size++; |
*ds = tgsi_build_declaration_semantic( |
full_decl->Semantic.Name, |
full_decl->Semantic.Index, |
declaration, |
header ); |
} |
if (full_decl->Declaration.File == TGSI_FILE_RESOURCE) { |
struct tgsi_declaration_resource *dr; |
if (maxsize <= size) { |
return 0; |
} |
dr = (struct tgsi_declaration_resource *)&tokens[size]; |
size++; |
*dr = tgsi_build_declaration_resource(full_decl->Resource.Resource, |
full_decl->Resource.Raw, |
full_decl->Resource.Writable, |
declaration, |
header); |
} |
if (full_decl->Declaration.File == TGSI_FILE_SAMPLER_VIEW) { |
struct tgsi_declaration_sampler_view *dsv; |
if (maxsize <= size) { |
return 0; |
} |
dsv = (struct tgsi_declaration_sampler_view *)&tokens[size]; |
size++; |
*dsv = tgsi_build_declaration_sampler_view( |
full_decl->SamplerView.Resource, |
full_decl->SamplerView.ReturnTypeX, |
full_decl->SamplerView.ReturnTypeY, |
full_decl->SamplerView.ReturnTypeZ, |
full_decl->SamplerView.ReturnTypeW, |
declaration, |
header); |
} |
return size; |
} |
/* |
* immediate |
*/ |
static struct tgsi_immediate |
tgsi_default_immediate( void ) |
{ |
struct tgsi_immediate immediate; |
immediate.Type = TGSI_TOKEN_TYPE_IMMEDIATE; |
immediate.NrTokens = 1; |
immediate.DataType = TGSI_IMM_FLOAT32; |
immediate.Padding = 0; |
return immediate; |
} |
static struct tgsi_immediate |
tgsi_build_immediate( |
struct tgsi_header *header, |
unsigned type ) |
{ |
struct tgsi_immediate immediate; |
immediate = tgsi_default_immediate(); |
immediate.DataType = type; |
header_bodysize_grow( header ); |
return immediate; |
} |
struct tgsi_full_immediate |
tgsi_default_full_immediate( void ) |
{ |
struct tgsi_full_immediate fullimm; |
fullimm.Immediate = tgsi_default_immediate(); |
fullimm.u[0].Float = 0.0f; |
fullimm.u[1].Float = 0.0f; |
fullimm.u[2].Float = 0.0f; |
fullimm.u[3].Float = 0.0f; |
return fullimm; |
} |
static void |
immediate_grow( |
struct tgsi_immediate *immediate, |
struct tgsi_header *header ) |
{ |
assert( immediate->NrTokens < 0xFF ); |
immediate->NrTokens++; |
header_bodysize_grow( header ); |
} |
unsigned |
tgsi_build_full_immediate( |
const struct tgsi_full_immediate *full_imm, |
struct tgsi_token *tokens, |
struct tgsi_header *header, |
unsigned maxsize ) |
{ |
unsigned size = 0, i; |
struct tgsi_immediate *immediate; |
if( maxsize <= size ) |
return 0; |
immediate = (struct tgsi_immediate *) &tokens[size]; |
size++; |
*immediate = tgsi_build_immediate( header, full_imm->Immediate.DataType ); |
assert( full_imm->Immediate.NrTokens <= 4 + 1 ); |
for( i = 0; i < full_imm->Immediate.NrTokens - 1; i++ ) { |
union tgsi_immediate_data *data; |
if( maxsize <= size ) |
return 0; |
data = (union tgsi_immediate_data *) &tokens[size]; |
*data = full_imm->u[i]; |
immediate_grow( immediate, header ); |
size++; |
} |
return size; |
} |
/* |
* instruction |
*/ |
struct tgsi_instruction |
tgsi_default_instruction( void ) |
{ |
struct tgsi_instruction instruction; |
instruction.Type = TGSI_TOKEN_TYPE_INSTRUCTION; |
instruction.NrTokens = 0; |
instruction.Opcode = TGSI_OPCODE_MOV; |
instruction.Saturate = TGSI_SAT_NONE; |
instruction.Predicate = 0; |
instruction.NumDstRegs = 1; |
instruction.NumSrcRegs = 1; |
instruction.Label = 0; |
instruction.Texture = 0; |
instruction.Padding = 0; |
return instruction; |
} |
static struct tgsi_instruction |
tgsi_build_instruction(unsigned opcode, |
unsigned saturate, |
unsigned predicate, |
unsigned num_dst_regs, |
unsigned num_src_regs, |
struct tgsi_header *header) |
{ |
struct tgsi_instruction instruction; |
assert (opcode <= TGSI_OPCODE_LAST); |
assert (saturate <= TGSI_SAT_MINUS_PLUS_ONE); |
assert (num_dst_regs <= 3); |
assert (num_src_regs <= 15); |
instruction = tgsi_default_instruction(); |
instruction.Opcode = opcode; |
instruction.Saturate = saturate; |
instruction.Predicate = predicate; |
instruction.NumDstRegs = num_dst_regs; |
instruction.NumSrcRegs = num_src_regs; |
header_bodysize_grow( header ); |
return instruction; |
} |
static void |
instruction_grow( |
struct tgsi_instruction *instruction, |
struct tgsi_header *header ) |
{ |
assert (instruction->NrTokens < 0xFF); |
instruction->NrTokens++; |
header_bodysize_grow( header ); |
} |
struct tgsi_instruction_predicate |
tgsi_default_instruction_predicate(void) |
{ |
struct tgsi_instruction_predicate instruction_predicate; |
instruction_predicate.SwizzleX = TGSI_SWIZZLE_X; |
instruction_predicate.SwizzleY = TGSI_SWIZZLE_Y; |
instruction_predicate.SwizzleZ = TGSI_SWIZZLE_Z; |
instruction_predicate.SwizzleW = TGSI_SWIZZLE_W; |
instruction_predicate.Negate = 0; |
instruction_predicate.Index = 0; |
instruction_predicate.Padding = 0; |
return instruction_predicate; |
} |
static struct tgsi_instruction_predicate |
tgsi_build_instruction_predicate(int index, |
unsigned negate, |
unsigned swizzleX, |
unsigned swizzleY, |
unsigned swizzleZ, |
unsigned swizzleW, |
struct tgsi_instruction *instruction, |
struct tgsi_header *header) |
{ |
struct tgsi_instruction_predicate instruction_predicate; |
instruction_predicate = tgsi_default_instruction_predicate(); |
instruction_predicate.SwizzleX = swizzleX; |
instruction_predicate.SwizzleY = swizzleY; |
instruction_predicate.SwizzleZ = swizzleZ; |
instruction_predicate.SwizzleW = swizzleW; |
instruction_predicate.Negate = negate; |
instruction_predicate.Index = index; |
instruction_grow(instruction, header); |
return instruction_predicate; |
} |
static struct tgsi_instruction_label |
tgsi_default_instruction_label( void ) |
{ |
struct tgsi_instruction_label instruction_label; |
instruction_label.Label = 0; |
instruction_label.Padding = 0; |
return instruction_label; |
} |
static struct tgsi_instruction_label |
tgsi_build_instruction_label( |
unsigned label, |
struct tgsi_token *prev_token, |
struct tgsi_instruction *instruction, |
struct tgsi_header *header ) |
{ |
struct tgsi_instruction_label instruction_label; |
instruction_label.Label = label; |
instruction_label.Padding = 0; |
instruction->Label = 1; |
instruction_grow( instruction, header ); |
return instruction_label; |
} |
static struct tgsi_instruction_texture |
tgsi_default_instruction_texture( void ) |
{ |
struct tgsi_instruction_texture instruction_texture; |
instruction_texture.Texture = TGSI_TEXTURE_UNKNOWN; |
instruction_texture.NumOffsets = 0; |
instruction_texture.Padding = 0; |
return instruction_texture; |
} |
static struct tgsi_instruction_texture |
tgsi_build_instruction_texture( |
unsigned texture, |
unsigned num_offsets, |
struct tgsi_token *prev_token, |
struct tgsi_instruction *instruction, |
struct tgsi_header *header ) |
{ |
struct tgsi_instruction_texture instruction_texture; |
instruction_texture.Texture = texture; |
instruction_texture.NumOffsets = num_offsets; |
instruction_texture.Padding = 0; |
instruction->Texture = 1; |
instruction_grow( instruction, header ); |
return instruction_texture; |
} |
static struct tgsi_texture_offset |
tgsi_default_texture_offset( void ) |
{ |
struct tgsi_texture_offset texture_offset; |
texture_offset.Index = 0; |
texture_offset.File = 0; |
texture_offset.SwizzleX = 0; |
texture_offset.SwizzleY = 0; |
texture_offset.SwizzleZ = 0; |
texture_offset.Padding = 0; |
return texture_offset; |
} |
static struct tgsi_texture_offset |
tgsi_build_texture_offset( |
int index, int file, int swizzle_x, int swizzle_y, int swizzle_z, |
struct tgsi_token *prev_token, |
struct tgsi_instruction *instruction, |
struct tgsi_header *header ) |
{ |
struct tgsi_texture_offset texture_offset; |
texture_offset.Index = index; |
texture_offset.File = file; |
texture_offset.SwizzleX = swizzle_x; |
texture_offset.SwizzleY = swizzle_y; |
texture_offset.SwizzleZ = swizzle_z; |
texture_offset.Padding = 0; |
instruction_grow( instruction, header ); |
return texture_offset; |
} |
static struct tgsi_src_register |
tgsi_default_src_register( void ) |
{ |
struct tgsi_src_register src_register; |
src_register.File = TGSI_FILE_NULL; |
src_register.SwizzleX = TGSI_SWIZZLE_X; |
src_register.SwizzleY = TGSI_SWIZZLE_Y; |
src_register.SwizzleZ = TGSI_SWIZZLE_Z; |
src_register.SwizzleW = TGSI_SWIZZLE_W; |
src_register.Negate = 0; |
src_register.Absolute = 0; |
src_register.Indirect = 0; |
src_register.Dimension = 0; |
src_register.Index = 0; |
return src_register; |
} |
static struct tgsi_src_register |
tgsi_build_src_register( |
unsigned file, |
unsigned swizzle_x, |
unsigned swizzle_y, |
unsigned swizzle_z, |
unsigned swizzle_w, |
unsigned negate, |
unsigned absolute, |
unsigned indirect, |
unsigned dimension, |
int index, |
struct tgsi_instruction *instruction, |
struct tgsi_header *header ) |
{ |
struct tgsi_src_register src_register; |
assert( file < TGSI_FILE_COUNT ); |
assert( swizzle_x <= TGSI_SWIZZLE_W ); |
assert( swizzle_y <= TGSI_SWIZZLE_W ); |
assert( swizzle_z <= TGSI_SWIZZLE_W ); |
assert( swizzle_w <= TGSI_SWIZZLE_W ); |
assert( negate <= 1 ); |
assert( index >= -0x8000 && index <= 0x7FFF ); |
src_register.File = file; |
src_register.SwizzleX = swizzle_x; |
src_register.SwizzleY = swizzle_y; |
src_register.SwizzleZ = swizzle_z; |
src_register.SwizzleW = swizzle_w; |
src_register.Negate = negate; |
src_register.Absolute = absolute; |
src_register.Indirect = indirect; |
src_register.Dimension = dimension; |
src_register.Index = index; |
instruction_grow( instruction, header ); |
return src_register; |
} |
static struct tgsi_ind_register |
tgsi_default_ind_register( void ) |
{ |
struct tgsi_ind_register ind_register; |
ind_register.File = TGSI_FILE_NULL; |
ind_register.Index = 0; |
ind_register.Swizzle = TGSI_SWIZZLE_X; |
ind_register.ArrayID = 0; |
return ind_register; |
} |
static struct tgsi_ind_register |
tgsi_build_ind_register( |
unsigned file, |
unsigned swizzle, |
unsigned arrayid, |
int index, |
struct tgsi_instruction *instruction, |
struct tgsi_header *header ) |
{ |
struct tgsi_ind_register ind_register; |
assert( file < TGSI_FILE_COUNT ); |
assert( swizzle <= TGSI_SWIZZLE_W ); |
assert( index >= -0x8000 && index <= 0x7FFF ); |
ind_register.File = file; |
ind_register.Swizzle = swizzle; |
ind_register.Index = index; |
ind_register.ArrayID = arrayid; |
instruction_grow( instruction, header ); |
return ind_register; |
} |
static struct tgsi_dimension |
tgsi_default_dimension( void ) |
{ |
struct tgsi_dimension dimension; |
dimension.Indirect = 0; |
dimension.Dimension = 0; |
dimension.Padding = 0; |
dimension.Index = 0; |
return dimension; |
} |
static struct tgsi_full_src_register |
tgsi_default_full_src_register( void ) |
{ |
struct tgsi_full_src_register full_src_register; |
full_src_register.Register = tgsi_default_src_register(); |
full_src_register.Indirect = tgsi_default_ind_register(); |
full_src_register.Dimension = tgsi_default_dimension(); |
full_src_register.DimIndirect = tgsi_default_ind_register(); |
return full_src_register; |
} |
static struct tgsi_dimension |
tgsi_build_dimension( |
unsigned indirect, |
unsigned index, |
struct tgsi_instruction *instruction, |
struct tgsi_header *header ) |
{ |
struct tgsi_dimension dimension; |
dimension.Indirect = indirect; |
dimension.Dimension = 0; |
dimension.Padding = 0; |
dimension.Index = index; |
instruction_grow( instruction, header ); |
return dimension; |
} |
static struct tgsi_dst_register |
tgsi_default_dst_register( void ) |
{ |
struct tgsi_dst_register dst_register; |
dst_register.File = TGSI_FILE_NULL; |
dst_register.WriteMask = TGSI_WRITEMASK_XYZW; |
dst_register.Indirect = 0; |
dst_register.Dimension = 0; |
dst_register.Index = 0; |
dst_register.Padding = 0; |
return dst_register; |
} |
static struct tgsi_dst_register |
tgsi_build_dst_register( |
unsigned file, |
unsigned mask, |
unsigned indirect, |
unsigned dimension, |
int index, |
struct tgsi_instruction *instruction, |
struct tgsi_header *header ) |
{ |
struct tgsi_dst_register dst_register; |
assert( file < TGSI_FILE_COUNT ); |
assert( mask <= TGSI_WRITEMASK_XYZW ); |
assert( index >= -32768 && index <= 32767 ); |
dst_register.File = file; |
dst_register.WriteMask = mask; |
dst_register.Indirect = indirect; |
dst_register.Dimension = dimension; |
dst_register.Index = index; |
dst_register.Padding = 0; |
instruction_grow( instruction, header ); |
return dst_register; |
} |
static struct tgsi_full_dst_register |
tgsi_default_full_dst_register( void ) |
{ |
struct tgsi_full_dst_register full_dst_register; |
full_dst_register.Register = tgsi_default_dst_register(); |
full_dst_register.Indirect = tgsi_default_ind_register(); |
full_dst_register.Dimension = tgsi_default_dimension(); |
full_dst_register.DimIndirect = tgsi_default_ind_register(); |
return full_dst_register; |
} |
struct tgsi_full_instruction |
tgsi_default_full_instruction( void ) |
{ |
struct tgsi_full_instruction full_instruction; |
unsigned i; |
full_instruction.Instruction = tgsi_default_instruction(); |
full_instruction.Predicate = tgsi_default_instruction_predicate(); |
full_instruction.Label = tgsi_default_instruction_label(); |
full_instruction.Texture = tgsi_default_instruction_texture(); |
for( i = 0; i < TGSI_FULL_MAX_TEX_OFFSETS; i++ ) { |
full_instruction.TexOffsets[i] = tgsi_default_texture_offset(); |
} |
for( i = 0; i < TGSI_FULL_MAX_DST_REGISTERS; i++ ) { |
full_instruction.Dst[i] = tgsi_default_full_dst_register(); |
} |
for( i = 0; i < TGSI_FULL_MAX_SRC_REGISTERS; i++ ) { |
full_instruction.Src[i] = tgsi_default_full_src_register(); |
} |
return full_instruction; |
} |
unsigned |
tgsi_build_full_instruction( |
const struct tgsi_full_instruction *full_inst, |
struct tgsi_token *tokens, |
struct tgsi_header *header, |
unsigned maxsize ) |
{ |
unsigned size = 0; |
unsigned i; |
struct tgsi_instruction *instruction; |
struct tgsi_token *prev_token; |
if( maxsize <= size ) |
return 0; |
instruction = (struct tgsi_instruction *) &tokens[size]; |
size++; |
*instruction = tgsi_build_instruction(full_inst->Instruction.Opcode, |
full_inst->Instruction.Saturate, |
full_inst->Instruction.Predicate, |
full_inst->Instruction.NumDstRegs, |
full_inst->Instruction.NumSrcRegs, |
header); |
prev_token = (struct tgsi_token *) instruction; |
if (full_inst->Instruction.Predicate) { |
struct tgsi_instruction_predicate *instruction_predicate; |
if (maxsize <= size) { |
return 0; |
} |
instruction_predicate = (struct tgsi_instruction_predicate *)&tokens[size]; |
size++; |
*instruction_predicate = |
tgsi_build_instruction_predicate(full_inst->Predicate.Index, |
full_inst->Predicate.Negate, |
full_inst->Predicate.SwizzleX, |
full_inst->Predicate.SwizzleY, |
full_inst->Predicate.SwizzleZ, |
full_inst->Predicate.SwizzleW, |
instruction, |
header); |
} |
if (full_inst->Instruction.Label) { |
struct tgsi_instruction_label *instruction_label; |
if( maxsize <= size ) |
return 0; |
instruction_label = |
(struct tgsi_instruction_label *) &tokens[size]; |
size++; |
*instruction_label = tgsi_build_instruction_label( |
full_inst->Label.Label, |
prev_token, |
instruction, |
header ); |
prev_token = (struct tgsi_token *) instruction_label; |
} |
if (full_inst->Instruction.Texture) { |
struct tgsi_instruction_texture *instruction_texture; |
if( maxsize <= size ) |
return 0; |
instruction_texture = |
(struct tgsi_instruction_texture *) &tokens[size]; |
size++; |
*instruction_texture = tgsi_build_instruction_texture( |
full_inst->Texture.Texture, |
full_inst->Texture.NumOffsets, |
prev_token, |
instruction, |
header ); |
prev_token = (struct tgsi_token *) instruction_texture; |
for (i = 0; i < full_inst->Texture.NumOffsets; i++) { |
struct tgsi_texture_offset *texture_offset; |
if ( maxsize <= size ) |
return 0; |
texture_offset = (struct tgsi_texture_offset *)&tokens[size]; |
size++; |
*texture_offset = tgsi_build_texture_offset( |
full_inst->TexOffsets[i].Index, |
full_inst->TexOffsets[i].File, |
full_inst->TexOffsets[i].SwizzleX, |
full_inst->TexOffsets[i].SwizzleY, |
full_inst->TexOffsets[i].SwizzleZ, |
prev_token, |
instruction, |
header); |
prev_token = (struct tgsi_token *) texture_offset; |
} |
} |
for( i = 0; i < full_inst->Instruction.NumDstRegs; i++ ) { |
const struct tgsi_full_dst_register *reg = &full_inst->Dst[i]; |
struct tgsi_dst_register *dst_register; |
if( maxsize <= size ) |
return 0; |
dst_register = (struct tgsi_dst_register *) &tokens[size]; |
size++; |
*dst_register = tgsi_build_dst_register( |
reg->Register.File, |
reg->Register.WriteMask, |
reg->Register.Indirect, |
reg->Register.Dimension, |
reg->Register.Index, |
instruction, |
header ); |
if( reg->Register.Indirect ) { |
struct tgsi_ind_register *ind; |
if( maxsize <= size ) |
return 0; |
ind = (struct tgsi_ind_register *) &tokens[size]; |
size++; |
*ind = tgsi_build_ind_register( |
reg->Indirect.File, |
reg->Indirect.Swizzle, |
reg->Indirect.Index, |
reg->Indirect.ArrayID, |
instruction, |
header ); |
} |
if( reg->Register.Dimension ) { |
struct tgsi_dimension *dim; |
assert( !reg->Dimension.Dimension ); |
if( maxsize <= size ) |
return 0; |
dim = (struct tgsi_dimension *) &tokens[size]; |
size++; |
*dim = tgsi_build_dimension( |
reg->Dimension.Indirect, |
reg->Dimension.Index, |
instruction, |
header ); |
if( reg->Dimension.Indirect ) { |
struct tgsi_ind_register *ind; |
if( maxsize <= size ) |
return 0; |
ind = (struct tgsi_ind_register *) &tokens[size]; |
size++; |
*ind = tgsi_build_ind_register( |
reg->DimIndirect.File, |
reg->DimIndirect.Swizzle, |
reg->DimIndirect.Index, |
reg->DimIndirect.ArrayID, |
instruction, |
header ); |
} |
} |
} |
for( i = 0; i < full_inst->Instruction.NumSrcRegs; i++ ) { |
const struct tgsi_full_src_register *reg = &full_inst->Src[i]; |
struct tgsi_src_register *src_register; |
if( maxsize <= size ) |
return 0; |
src_register = (struct tgsi_src_register *) &tokens[size]; |
size++; |
*src_register = tgsi_build_src_register( |
reg->Register.File, |
reg->Register.SwizzleX, |
reg->Register.SwizzleY, |
reg->Register.SwizzleZ, |
reg->Register.SwizzleW, |
reg->Register.Negate, |
reg->Register.Absolute, |
reg->Register.Indirect, |
reg->Register.Dimension, |
reg->Register.Index, |
instruction, |
header ); |
if( reg->Register.Indirect ) { |
struct tgsi_ind_register *ind; |
if( maxsize <= size ) |
return 0; |
ind = (struct tgsi_ind_register *) &tokens[size]; |
size++; |
*ind = tgsi_build_ind_register( |
reg->Indirect.File, |
reg->Indirect.Swizzle, |
reg->Indirect.Index, |
reg->Indirect.ArrayID, |
instruction, |
header ); |
} |
if( reg->Register.Dimension ) { |
struct tgsi_dimension *dim; |
assert( !reg->Dimension.Dimension ); |
if( maxsize <= size ) |
return 0; |
dim = (struct tgsi_dimension *) &tokens[size]; |
size++; |
*dim = tgsi_build_dimension( |
reg->Dimension.Indirect, |
reg->Dimension.Index, |
instruction, |
header ); |
if( reg->Dimension.Indirect ) { |
struct tgsi_ind_register *ind; |
if( maxsize <= size ) |
return 0; |
ind = (struct tgsi_ind_register *) &tokens[size]; |
size++; |
*ind = tgsi_build_ind_register( |
reg->DimIndirect.File, |
reg->DimIndirect.Swizzle, |
reg->DimIndirect.Index, |
reg->DimIndirect.ArrayID, |
instruction, |
header ); |
} |
} |
} |
return size; |
} |
static struct tgsi_property |
tgsi_default_property( void ) |
{ |
struct tgsi_property property; |
property.Type = TGSI_TOKEN_TYPE_PROPERTY; |
property.NrTokens = 1; |
property.PropertyName = TGSI_PROPERTY_GS_INPUT_PRIM; |
property.Padding = 0; |
return property; |
} |
static struct tgsi_property |
tgsi_build_property(unsigned property_name, |
struct tgsi_header *header) |
{ |
struct tgsi_property property; |
property = tgsi_default_property(); |
property.PropertyName = property_name; |
header_bodysize_grow( header ); |
return property; |
} |
struct tgsi_full_property |
tgsi_default_full_property( void ) |
{ |
struct tgsi_full_property full_property; |
full_property.Property = tgsi_default_property(); |
memset(full_property.u, 0, |
sizeof(struct tgsi_property_data) * 8); |
return full_property; |
} |
static void |
property_grow( |
struct tgsi_property *property, |
struct tgsi_header *header ) |
{ |
assert( property->NrTokens < 0xFF ); |
property->NrTokens++; |
header_bodysize_grow( header ); |
} |
static struct tgsi_property_data |
tgsi_build_property_data( |
unsigned value, |
struct tgsi_property *property, |
struct tgsi_header *header ) |
{ |
struct tgsi_property_data property_data; |
property_data.Data = value; |
property_grow( property, header ); |
return property_data; |
} |
unsigned |
tgsi_build_full_property( |
const struct tgsi_full_property *full_prop, |
struct tgsi_token *tokens, |
struct tgsi_header *header, |
unsigned maxsize ) |
{ |
unsigned size = 0, i; |
struct tgsi_property *property; |
if( maxsize <= size ) |
return 0; |
property = (struct tgsi_property *) &tokens[size]; |
size++; |
*property = tgsi_build_property( |
full_prop->Property.PropertyName, |
header ); |
assert( full_prop->Property.NrTokens <= 8 + 1 ); |
for( i = 0; i < full_prop->Property.NrTokens - 1; i++ ) { |
struct tgsi_property_data *data; |
if( maxsize <= size ) |
return 0; |
data = (struct tgsi_property_data *) &tokens[size]; |
size++; |
*data = tgsi_build_property_data( |
full_prop->u[i].Data, |
property, |
header ); |
} |
return size; |
} |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_build.h |
---|
0,0 → 1,118 |
/************************************************************************** |
* |
* Copyright 2007 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. |
* |
**************************************************************************/ |
#ifndef TGSI_BUILD_H |
#define TGSI_BUILD_H |
struct tgsi_token; |
#if defined __cplusplus |
extern "C" { |
#endif |
/* |
* header |
*/ |
struct tgsi_header |
tgsi_build_header( void ); |
struct tgsi_processor |
tgsi_build_processor( |
unsigned processor, |
struct tgsi_header *header ); |
/* |
* declaration |
*/ |
struct tgsi_full_declaration |
tgsi_default_full_declaration( void ); |
unsigned |
tgsi_build_full_declaration( |
const struct tgsi_full_declaration *full_decl, |
struct tgsi_token *tokens, |
struct tgsi_header *header, |
unsigned maxsize ); |
/* |
* immediate |
*/ |
struct tgsi_full_immediate |
tgsi_default_full_immediate( void ); |
unsigned |
tgsi_build_full_immediate( |
const struct tgsi_full_immediate *full_imm, |
struct tgsi_token *tokens, |
struct tgsi_header *header, |
unsigned maxsize ); |
/* |
* properties |
*/ |
struct tgsi_full_property |
tgsi_default_full_property( void ); |
unsigned |
tgsi_build_full_property( |
const struct tgsi_full_property *full_prop, |
struct tgsi_token *tokens, |
struct tgsi_header *header, |
unsigned maxsize ); |
/* |
* instruction |
*/ |
struct tgsi_instruction |
tgsi_default_instruction( void ); |
struct tgsi_full_instruction |
tgsi_default_full_instruction( void ); |
unsigned |
tgsi_build_full_instruction( |
const struct tgsi_full_instruction *full_inst, |
struct tgsi_token *tokens, |
struct tgsi_header *header, |
unsigned maxsize ); |
struct tgsi_instruction_predicate |
tgsi_default_instruction_predicate(void); |
#if defined __cplusplus |
} |
#endif |
#endif /* TGSI_BUILD_H */ |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_dump.c |
---|
0,0 → 1,723 |
/************************************************************************** |
* |
* Copyright 2007-2008 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 "util/u_debug.h" |
#include "util/u_string.h" |
#include "util/u_math.h" |
#include "util/u_memory.h" |
#include "tgsi_dump.h" |
#include "tgsi_info.h" |
#include "tgsi_iterate.h" |
#include "tgsi_strings.h" |
/** Number of spaces to indent for IF/LOOP/etc */ |
static const int indent_spaces = 3; |
struct dump_ctx |
{ |
struct tgsi_iterate_context iter; |
uint instno; |
uint immno; |
int indent; |
uint indentation; |
void (*dump_printf)(struct dump_ctx *ctx, const char *format, ...); |
}; |
static void |
dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...) |
{ |
va_list ap; |
(void)ctx; |
va_start(ap, format); |
_debug_vprintf(format, ap); |
va_end(ap); |
} |
static void |
dump_enum( |
struct dump_ctx *ctx, |
uint e, |
const char **enums, |
uint enum_count ) |
{ |
if (e >= enum_count) |
ctx->dump_printf( ctx, "%u", e ); |
else |
ctx->dump_printf( ctx, "%s", enums[e] ); |
} |
#define EOL() ctx->dump_printf( ctx, "\n" ) |
#define TXT(S) ctx->dump_printf( ctx, "%s", S ) |
#define CHR(C) ctx->dump_printf( ctx, "%c", C ) |
#define UIX(I) ctx->dump_printf( ctx, "0x%x", I ) |
#define UID(I) ctx->dump_printf( ctx, "%u", I ) |
#define INSTID(I) ctx->dump_printf( ctx, "% 3u", I ) |
#define SID(I) ctx->dump_printf( ctx, "%d", I ) |
#define FLT(F) ctx->dump_printf( ctx, "%10.4f", F ) |
#define ENM(E,ENUMS) dump_enum( ctx, E, ENUMS, sizeof( ENUMS ) / sizeof( *ENUMS ) ) |
const char * |
tgsi_swizzle_names[4] = |
{ |
"x", |
"y", |
"z", |
"w" |
}; |
static void |
_dump_register_src( |
struct dump_ctx *ctx, |
const struct tgsi_full_src_register *src ) |
{ |
TXT(tgsi_file_name(src->Register.File)); |
if (src->Register.Dimension) { |
if (src->Dimension.Indirect) { |
CHR( '[' ); |
TXT(tgsi_file_name(src->DimIndirect.File)); |
CHR( '[' ); |
SID( src->DimIndirect.Index ); |
TXT( "]." ); |
ENM( src->DimIndirect.Swizzle, tgsi_swizzle_names ); |
if (src->Dimension.Index != 0) { |
if (src->Dimension.Index > 0) |
CHR( '+' ); |
SID( src->Dimension.Index ); |
} |
CHR( ']' ); |
if (src->DimIndirect.ArrayID) { |
CHR( '(' ); |
SID( src->DimIndirect.ArrayID ); |
CHR( ')' ); |
} |
} else { |
CHR('['); |
SID(src->Dimension.Index); |
CHR(']'); |
} |
} |
if (src->Register.Indirect) { |
CHR( '[' ); |
TXT(tgsi_file_name(src->Indirect.File)); |
CHR( '[' ); |
SID( src->Indirect.Index ); |
TXT( "]." ); |
ENM( src->Indirect.Swizzle, tgsi_swizzle_names ); |
if (src->Register.Index != 0) { |
if (src->Register.Index > 0) |
CHR( '+' ); |
SID( src->Register.Index ); |
} |
CHR( ']' ); |
if (src->Indirect.ArrayID) { |
CHR( '(' ); |
SID( src->Indirect.ArrayID ); |
CHR( ')' ); |
} |
} else { |
CHR( '[' ); |
SID( src->Register.Index ); |
CHR( ']' ); |
} |
} |
static void |
_dump_register_dst( |
struct dump_ctx *ctx, |
const struct tgsi_full_dst_register *dst ) |
{ |
TXT(tgsi_file_name(dst->Register.File)); |
if (dst->Register.Dimension) { |
if (dst->Dimension.Indirect) { |
CHR( '[' ); |
TXT(tgsi_file_name(dst->DimIndirect.File)); |
CHR( '[' ); |
SID( dst->DimIndirect.Index ); |
TXT( "]." ); |
ENM( dst->DimIndirect.Swizzle, tgsi_swizzle_names ); |
if (dst->Dimension.Index != 0) { |
if (dst->Dimension.Index > 0) |
CHR( '+' ); |
SID( dst->Dimension.Index ); |
} |
CHR( ']' ); |
if (dst->DimIndirect.ArrayID) { |
CHR( '(' ); |
SID( dst->DimIndirect.ArrayID ); |
CHR( ')' ); |
} |
} else { |
CHR('['); |
SID(dst->Dimension.Index); |
CHR(']'); |
} |
} |
if (dst->Register.Indirect) { |
CHR( '[' ); |
TXT(tgsi_file_name(dst->Indirect.File)); |
CHR( '[' ); |
SID( dst->Indirect.Index ); |
TXT( "]." ); |
ENM( dst->Indirect.Swizzle, tgsi_swizzle_names ); |
if (dst->Register.Index != 0) { |
if (dst->Register.Index > 0) |
CHR( '+' ); |
SID( dst->Register.Index ); |
} |
CHR( ']' ); |
if (dst->Indirect.ArrayID) { |
CHR( '(' ); |
SID( dst->Indirect.ArrayID ); |
CHR( ')' ); |
} |
} else { |
CHR( '[' ); |
SID( dst->Register.Index ); |
CHR( ']' ); |
} |
} |
static void |
_dump_writemask( |
struct dump_ctx *ctx, |
uint writemask ) |
{ |
if (writemask != TGSI_WRITEMASK_XYZW) { |
CHR( '.' ); |
if (writemask & TGSI_WRITEMASK_X) |
CHR( 'x' ); |
if (writemask & TGSI_WRITEMASK_Y) |
CHR( 'y' ); |
if (writemask & TGSI_WRITEMASK_Z) |
CHR( 'z' ); |
if (writemask & TGSI_WRITEMASK_W) |
CHR( 'w' ); |
} |
} |
static void |
dump_imm_data(struct tgsi_iterate_context *iter, |
union tgsi_immediate_data *data, |
unsigned num_tokens, |
unsigned data_type) |
{ |
struct dump_ctx *ctx = (struct dump_ctx *)iter; |
unsigned i ; |
TXT( " {" ); |
assert( num_tokens <= 4 ); |
for (i = 0; i < num_tokens; i++) { |
switch (data_type) { |
case TGSI_IMM_FLOAT32: |
FLT( data[i].Float ); |
break; |
case TGSI_IMM_UINT32: |
UID(data[i].Uint); |
break; |
case TGSI_IMM_INT32: |
SID(data[i].Int); |
break; |
default: |
assert( 0 ); |
} |
if (i < num_tokens - 1) |
TXT( ", " ); |
} |
TXT( "}" ); |
} |
static boolean |
iter_declaration( |
struct tgsi_iterate_context *iter, |
struct tgsi_full_declaration *decl ) |
{ |
struct dump_ctx *ctx = (struct dump_ctx *)iter; |
TXT( "DCL " ); |
TXT(tgsi_file_name(decl->Declaration.File)); |
/* all geometry shader inputs are two dimensional */ |
if (decl->Declaration.File == TGSI_FILE_INPUT && |
iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) { |
TXT("[]"); |
} |
if (decl->Declaration.Dimension) { |
CHR('['); |
SID(decl->Dim.Index2D); |
CHR(']'); |
} |
CHR('['); |
SID(decl->Range.First); |
if (decl->Range.First != decl->Range.Last) { |
TXT(".."); |
SID(decl->Range.Last); |
} |
CHR(']'); |
_dump_writemask( |
ctx, |
decl->Declaration.UsageMask ); |
if (decl->Declaration.Array) { |
TXT( ", ARRAY(" ); |
SID(decl->Array.ArrayID); |
CHR(')'); |
} |
if (decl->Declaration.Local) |
TXT( ", LOCAL" ); |
if (decl->Declaration.Semantic) { |
TXT( ", " ); |
ENM( decl->Semantic.Name, tgsi_semantic_names ); |
if (decl->Semantic.Index != 0 || |
decl->Semantic.Name == TGSI_SEMANTIC_TEXCOORD || |
decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) { |
CHR( '[' ); |
UID( decl->Semantic.Index ); |
CHR( ']' ); |
} |
} |
if (decl->Declaration.File == TGSI_FILE_RESOURCE) { |
TXT(", "); |
ENM(decl->Resource.Resource, tgsi_texture_names); |
if (decl->Resource.Writable) |
TXT(", WR"); |
if (decl->Resource.Raw) |
TXT(", RAW"); |
} |
if (decl->Declaration.File == TGSI_FILE_SAMPLER_VIEW) { |
TXT(", "); |
ENM(decl->SamplerView.Resource, tgsi_texture_names); |
TXT(", "); |
if ((decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeY) && |
(decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeZ) && |
(decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeW)) { |
ENM(decl->SamplerView.ReturnTypeX, tgsi_type_names); |
} else { |
ENM(decl->SamplerView.ReturnTypeX, tgsi_type_names); |
TXT(", "); |
ENM(decl->SamplerView.ReturnTypeY, tgsi_type_names); |
TXT(", "); |
ENM(decl->SamplerView.ReturnTypeZ, tgsi_type_names); |
TXT(", "); |
ENM(decl->SamplerView.ReturnTypeW, tgsi_type_names); |
} |
} |
if (decl->Declaration.Interpolate) { |
if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT && |
decl->Declaration.File == TGSI_FILE_INPUT) |
{ |
TXT( ", " ); |
ENM( decl->Interp.Interpolate, tgsi_interpolate_names ); |
} |
if (decl->Interp.Centroid) { |
TXT( ", CENTROID" ); |
} |
if (decl->Interp.CylindricalWrap) { |
TXT(", CYLWRAP_"); |
if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_X) { |
CHR('X'); |
} |
if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Y) { |
CHR('Y'); |
} |
if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Z) { |
CHR('Z'); |
} |
if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_W) { |
CHR('W'); |
} |
} |
} |
if (decl->Declaration.Invariant) { |
TXT( ", INVARIANT" ); |
} |
EOL(); |
return TRUE; |
} |
void |
tgsi_dump_declaration( |
const struct tgsi_full_declaration *decl ) |
{ |
struct dump_ctx ctx; |
ctx.dump_printf = dump_ctx_printf; |
iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl ); |
} |
static boolean |
iter_property( |
struct tgsi_iterate_context *iter, |
struct tgsi_full_property *prop ) |
{ |
unsigned i; |
struct dump_ctx *ctx = (struct dump_ctx *)iter; |
TXT( "PROPERTY " ); |
ENM(prop->Property.PropertyName, tgsi_property_names); |
if (prop->Property.NrTokens > 1) |
TXT(" "); |
for (i = 0; i < prop->Property.NrTokens - 1; ++i) { |
switch (prop->Property.PropertyName) { |
case TGSI_PROPERTY_GS_INPUT_PRIM: |
case TGSI_PROPERTY_GS_OUTPUT_PRIM: |
ENM(prop->u[i].Data, tgsi_primitive_names); |
break; |
case TGSI_PROPERTY_FS_COORD_ORIGIN: |
ENM(prop->u[i].Data, tgsi_fs_coord_origin_names); |
break; |
case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: |
ENM(prop->u[i].Data, tgsi_fs_coord_pixel_center_names); |
break; |
default: |
SID( prop->u[i].Data ); |
break; |
} |
if (i < prop->Property.NrTokens - 2) |
TXT( ", " ); |
} |
EOL(); |
return TRUE; |
} |
void tgsi_dump_property( |
const struct tgsi_full_property *prop ) |
{ |
struct dump_ctx ctx; |
ctx.dump_printf = dump_ctx_printf; |
iter_property( &ctx.iter, (struct tgsi_full_property *)prop ); |
} |
static boolean |
iter_immediate( |
struct tgsi_iterate_context *iter, |
struct tgsi_full_immediate *imm ) |
{ |
struct dump_ctx *ctx = (struct dump_ctx *) iter; |
TXT( "IMM[" ); |
SID( ctx->immno++ ); |
TXT( "] " ); |
ENM( imm->Immediate.DataType, tgsi_immediate_type_names ); |
dump_imm_data(iter, imm->u, imm->Immediate.NrTokens - 1, |
imm->Immediate.DataType); |
EOL(); |
return TRUE; |
} |
void |
tgsi_dump_immediate( |
const struct tgsi_full_immediate *imm ) |
{ |
struct dump_ctx ctx; |
ctx.dump_printf = dump_ctx_printf; |
iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm ); |
} |
static boolean |
iter_instruction( |
struct tgsi_iterate_context *iter, |
struct tgsi_full_instruction *inst ) |
{ |
struct dump_ctx *ctx = (struct dump_ctx *) iter; |
uint instno = ctx->instno++; |
const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode ); |
uint i; |
boolean first_reg = TRUE; |
INSTID( instno ); |
TXT( ": " ); |
ctx->indent -= info->pre_dedent; |
for(i = 0; (int)i < ctx->indent; ++i) |
TXT( " " ); |
ctx->indent += info->post_indent; |
if (inst->Instruction.Predicate) { |
CHR( '(' ); |
if (inst->Predicate.Negate) |
CHR( '!' ); |
TXT( "PRED[" ); |
SID( inst->Predicate.Index ); |
CHR( ']' ); |
if (inst->Predicate.SwizzleX != TGSI_SWIZZLE_X || |
inst->Predicate.SwizzleY != TGSI_SWIZZLE_Y || |
inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z || |
inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) { |
CHR( '.' ); |
ENM( inst->Predicate.SwizzleX, tgsi_swizzle_names ); |
ENM( inst->Predicate.SwizzleY, tgsi_swizzle_names ); |
ENM( inst->Predicate.SwizzleZ, tgsi_swizzle_names ); |
ENM( inst->Predicate.SwizzleW, tgsi_swizzle_names ); |
} |
TXT( ") " ); |
} |
TXT( info->mnemonic ); |
switch (inst->Instruction.Saturate) { |
case TGSI_SAT_NONE: |
break; |
case TGSI_SAT_ZERO_ONE: |
TXT( "_SAT" ); |
break; |
case TGSI_SAT_MINUS_PLUS_ONE: |
TXT( "_SATNV" ); |
break; |
default: |
assert( 0 ); |
} |
for (i = 0; i < inst->Instruction.NumDstRegs; i++) { |
const struct tgsi_full_dst_register *dst = &inst->Dst[i]; |
if (!first_reg) |
CHR( ',' ); |
CHR( ' ' ); |
_dump_register_dst( ctx, dst ); |
_dump_writemask( ctx, dst->Register.WriteMask ); |
first_reg = FALSE; |
} |
for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { |
const struct tgsi_full_src_register *src = &inst->Src[i]; |
if (!first_reg) |
CHR( ',' ); |
CHR( ' ' ); |
if (src->Register.Negate) |
CHR( '-' ); |
if (src->Register.Absolute) |
CHR( '|' ); |
_dump_register_src(ctx, src); |
if (src->Register.SwizzleX != TGSI_SWIZZLE_X || |
src->Register.SwizzleY != TGSI_SWIZZLE_Y || |
src->Register.SwizzleZ != TGSI_SWIZZLE_Z || |
src->Register.SwizzleW != TGSI_SWIZZLE_W) { |
CHR( '.' ); |
ENM( src->Register.SwizzleX, tgsi_swizzle_names ); |
ENM( src->Register.SwizzleY, tgsi_swizzle_names ); |
ENM( src->Register.SwizzleZ, tgsi_swizzle_names ); |
ENM( src->Register.SwizzleW, tgsi_swizzle_names ); |
} |
if (src->Register.Absolute) |
CHR( '|' ); |
first_reg = FALSE; |
} |
if (inst->Instruction.Texture) { |
TXT( ", " ); |
ENM( inst->Texture.Texture, tgsi_texture_names ); |
for (i = 0; i < inst->Texture.NumOffsets; i++) { |
TXT( ", " ); |
TXT(tgsi_file_name(inst->TexOffsets[i].File)); |
CHR( '[' ); |
SID( inst->TexOffsets[i].Index ); |
CHR( ']' ); |
CHR( '.' ); |
ENM( inst->TexOffsets[i].SwizzleX, tgsi_swizzle_names); |
ENM( inst->TexOffsets[i].SwizzleY, tgsi_swizzle_names); |
ENM( inst->TexOffsets[i].SwizzleZ, tgsi_swizzle_names); |
} |
} |
switch (inst->Instruction.Opcode) { |
case TGSI_OPCODE_IF: |
case TGSI_OPCODE_UIF: |
case TGSI_OPCODE_ELSE: |
case TGSI_OPCODE_BGNLOOP: |
case TGSI_OPCODE_ENDLOOP: |
case TGSI_OPCODE_CAL: |
TXT( " :" ); |
UID( inst->Label.Label ); |
break; |
} |
/* update indentation */ |
if (inst->Instruction.Opcode == TGSI_OPCODE_IF || |
inst->Instruction.Opcode == TGSI_OPCODE_UIF || |
inst->Instruction.Opcode == TGSI_OPCODE_ELSE || |
inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) { |
ctx->indentation += indent_spaces; |
} |
EOL(); |
return TRUE; |
} |
void |
tgsi_dump_instruction( |
const struct tgsi_full_instruction *inst, |
uint instno ) |
{ |
struct dump_ctx ctx; |
ctx.instno = instno; |
ctx.immno = instno; |
ctx.indent = 0; |
ctx.dump_printf = dump_ctx_printf; |
ctx.indentation = 0; |
iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst ); |
} |
static boolean |
prolog( |
struct tgsi_iterate_context *iter ) |
{ |
struct dump_ctx *ctx = (struct dump_ctx *) iter; |
ENM( iter->processor.Processor, tgsi_processor_type_names ); |
EOL(); |
return TRUE; |
} |
void |
tgsi_dump( |
const struct tgsi_token *tokens, |
uint flags ) |
{ |
struct dump_ctx ctx; |
ctx.iter.prolog = prolog; |
ctx.iter.iterate_instruction = iter_instruction; |
ctx.iter.iterate_declaration = iter_declaration; |
ctx.iter.iterate_immediate = iter_immediate; |
ctx.iter.iterate_property = iter_property; |
ctx.iter.epilog = NULL; |
ctx.instno = 0; |
ctx.immno = 0; |
ctx.indent = 0; |
ctx.dump_printf = dump_ctx_printf; |
ctx.indentation = 0; |
tgsi_iterate_shader( tokens, &ctx.iter ); |
} |
struct str_dump_ctx |
{ |
struct dump_ctx base; |
char *str; |
char *ptr; |
int left; |
}; |
static void |
str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...) |
{ |
struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx; |
if(sctx->left > 1) { |
int written; |
va_list ap; |
va_start(ap, format); |
written = util_vsnprintf(sctx->ptr, sctx->left, format, ap); |
va_end(ap); |
/* Some complicated logic needed to handle the return value of |
* vsnprintf: |
*/ |
if (written > 0) { |
written = MIN2(sctx->left, written); |
sctx->ptr += written; |
sctx->left -= written; |
} |
} |
} |
void |
tgsi_dump_str( |
const struct tgsi_token *tokens, |
uint flags, |
char *str, |
size_t size) |
{ |
struct str_dump_ctx ctx; |
ctx.base.iter.prolog = prolog; |
ctx.base.iter.iterate_instruction = iter_instruction; |
ctx.base.iter.iterate_declaration = iter_declaration; |
ctx.base.iter.iterate_immediate = iter_immediate; |
ctx.base.iter.iterate_property = iter_property; |
ctx.base.iter.epilog = NULL; |
ctx.base.instno = 0; |
ctx.base.immno = 0; |
ctx.base.indent = 0; |
ctx.base.dump_printf = &str_dump_ctx_printf; |
ctx.base.indentation = 0; |
ctx.str = str; |
ctx.str[0] = 0; |
ctx.ptr = str; |
ctx.left = (int)size; |
tgsi_iterate_shader( tokens, &ctx.base.iter ); |
} |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_dump.h |
---|
0,0 → 1,77 |
/************************************************************************** |
* |
* Copyright 2007-2008 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. |
* |
**************************************************************************/ |
#ifndef TGSI_DUMP_H |
#define TGSI_DUMP_H |
#include "pipe/p_compiler.h" |
#include "pipe/p_defines.h" |
#include "pipe/p_shader_tokens.h" |
#if defined __cplusplus |
extern "C" { |
#endif |
void |
tgsi_dump_str( |
const struct tgsi_token *tokens, |
uint flags, |
char *str, |
size_t size); |
void |
tgsi_dump( |
const struct tgsi_token *tokens, |
uint flags ); |
struct tgsi_full_immediate; |
struct tgsi_full_instruction; |
struct tgsi_full_declaration; |
struct tgsi_full_property; |
void |
tgsi_dump_immediate( |
const struct tgsi_full_immediate *imm ); |
void |
tgsi_dump_instruction( |
const struct tgsi_full_instruction *inst, |
uint instno ); |
void |
tgsi_dump_declaration( |
const struct tgsi_full_declaration *decl ); |
void |
tgsi_dump_property( |
const struct tgsi_full_property *prop ); |
#if defined __cplusplus |
} |
#endif |
#endif /* TGSI_DUMP_H */ |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_exec.c |
---|
0,0 → 1,4430 |
/************************************************************************** |
* |
* Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. |
* All Rights Reserved. |
* Copyright 2009-2010 VMware, Inc. 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. |
* |
**************************************************************************/ |
/** |
* TGSI interpreter/executor. |
* |
* Flow control information: |
* |
* Since we operate on 'quads' (4 pixels or 4 vertices in parallel) |
* flow control statements (IF/ELSE/ENDIF, LOOP/ENDLOOP) require special |
* care since a condition may be true for some quad components but false |
* for other components. |
* |
* We basically execute all statements (even if they're in the part of |
* an IF/ELSE clause that's "not taken") and use a special mask to |
* control writing to destination registers. This is the ExecMask. |
* See store_dest(). |
* |
* The ExecMask is computed from three other masks (CondMask, LoopMask and |
* ContMask) which are controlled by the flow control instructions (namely: |
* (IF/ELSE/ENDIF, LOOP/ENDLOOP and CONT). |
* |
* |
* Authors: |
* Michal Krol |
* Brian Paul |
*/ |
#include "pipe/p_compiler.h" |
#include "pipe/p_state.h" |
#include "pipe/p_shader_tokens.h" |
#include "tgsi/tgsi_dump.h" |
#include "tgsi/tgsi_parse.h" |
#include "tgsi/tgsi_util.h" |
#include "tgsi_exec.h" |
#include "util/u_memory.h" |
#include "util/u_math.h" |
#define DEBUG_EXECUTION 0 |
#define FAST_MATH 0 |
#define TILE_TOP_LEFT 0 |
#define TILE_TOP_RIGHT 1 |
#define TILE_BOTTOM_LEFT 2 |
#define TILE_BOTTOM_RIGHT 3 |
static void |
micro_abs(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = fabsf(src->f[0]); |
dst->f[1] = fabsf(src->f[1]); |
dst->f[2] = fabsf(src->f[2]); |
dst->f[3] = fabsf(src->f[3]); |
} |
static void |
micro_arl(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->i[0] = (int)floorf(src->f[0]); |
dst->i[1] = (int)floorf(src->f[1]); |
dst->i[2] = (int)floorf(src->f[2]); |
dst->i[3] = (int)floorf(src->f[3]); |
} |
static void |
micro_arr(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->i[0] = (int)floorf(src->f[0] + 0.5f); |
dst->i[1] = (int)floorf(src->f[1] + 0.5f); |
dst->i[2] = (int)floorf(src->f[2] + 0.5f); |
dst->i[3] = (int)floorf(src->f[3] + 0.5f); |
} |
static void |
micro_ceil(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = ceilf(src->f[0]); |
dst->f[1] = ceilf(src->f[1]); |
dst->f[2] = ceilf(src->f[2]); |
dst->f[3] = ceilf(src->f[3]); |
} |
static void |
micro_clamp(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1, |
const union tgsi_exec_channel *src2) |
{ |
dst->f[0] = src0->f[0] < src1->f[0] ? src1->f[0] : src0->f[0] > src2->f[0] ? src2->f[0] : src0->f[0]; |
dst->f[1] = src0->f[1] < src1->f[1] ? src1->f[1] : src0->f[1] > src2->f[1] ? src2->f[1] : src0->f[1]; |
dst->f[2] = src0->f[2] < src1->f[2] ? src1->f[2] : src0->f[2] > src2->f[2] ? src2->f[2] : src0->f[2]; |
dst->f[3] = src0->f[3] < src1->f[3] ? src1->f[3] : src0->f[3] > src2->f[3] ? src2->f[3] : src0->f[3]; |
} |
static void |
micro_cmp(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1, |
const union tgsi_exec_channel *src2) |
{ |
dst->f[0] = src0->f[0] < 0.0f ? src1->f[0] : src2->f[0]; |
dst->f[1] = src0->f[1] < 0.0f ? src1->f[1] : src2->f[1]; |
dst->f[2] = src0->f[2] < 0.0f ? src1->f[2] : src2->f[2]; |
dst->f[3] = src0->f[3] < 0.0f ? src1->f[3] : src2->f[3]; |
} |
static void |
micro_cnd(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1, |
const union tgsi_exec_channel *src2) |
{ |
dst->f[0] = src2->f[0] > 0.5f ? src0->f[0] : src1->f[0]; |
dst->f[1] = src2->f[1] > 0.5f ? src0->f[1] : src1->f[1]; |
dst->f[2] = src2->f[2] > 0.5f ? src0->f[2] : src1->f[2]; |
dst->f[3] = src2->f[3] > 0.5f ? src0->f[3] : src1->f[3]; |
} |
static void |
micro_cos(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = cosf(src->f[0]); |
dst->f[1] = cosf(src->f[1]); |
dst->f[2] = cosf(src->f[2]); |
dst->f[3] = cosf(src->f[3]); |
} |
static void |
micro_ddx(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = |
dst->f[1] = |
dst->f[2] = |
dst->f[3] = src->f[TILE_BOTTOM_RIGHT] - src->f[TILE_BOTTOM_LEFT]; |
} |
static void |
micro_ddy(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = |
dst->f[1] = |
dst->f[2] = |
dst->f[3] = src->f[TILE_BOTTOM_LEFT] - src->f[TILE_TOP_LEFT]; |
} |
static void |
micro_exp2(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
#if FAST_MATH |
dst->f[0] = util_fast_exp2(src->f[0]); |
dst->f[1] = util_fast_exp2(src->f[1]); |
dst->f[2] = util_fast_exp2(src->f[2]); |
dst->f[3] = util_fast_exp2(src->f[3]); |
#else |
#if DEBUG |
/* Inf is okay for this instruction, so clamp it to silence assertions. */ |
uint i; |
union tgsi_exec_channel clamped; |
for (i = 0; i < 4; i++) { |
if (src->f[i] > 127.99999f) { |
clamped.f[i] = 127.99999f; |
} else if (src->f[i] < -126.99999f) { |
clamped.f[i] = -126.99999f; |
} else { |
clamped.f[i] = src->f[i]; |
} |
} |
src = &clamped; |
#endif /* DEBUG */ |
dst->f[0] = powf(2.0f, src->f[0]); |
dst->f[1] = powf(2.0f, src->f[1]); |
dst->f[2] = powf(2.0f, src->f[2]); |
dst->f[3] = powf(2.0f, src->f[3]); |
#endif /* FAST_MATH */ |
} |
static void |
micro_flr(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = floorf(src->f[0]); |
dst->f[1] = floorf(src->f[1]); |
dst->f[2] = floorf(src->f[2]); |
dst->f[3] = floorf(src->f[3]); |
} |
static void |
micro_frc(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = src->f[0] - floorf(src->f[0]); |
dst->f[1] = src->f[1] - floorf(src->f[1]); |
dst->f[2] = src->f[2] - floorf(src->f[2]); |
dst->f[3] = src->f[3] - floorf(src->f[3]); |
} |
static void |
micro_iabs(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->i[0] = src->i[0] >= 0 ? src->i[0] : -src->i[0]; |
dst->i[1] = src->i[1] >= 0 ? src->i[1] : -src->i[1]; |
dst->i[2] = src->i[2] >= 0 ? src->i[2] : -src->i[2]; |
dst->i[3] = src->i[3] >= 0 ? src->i[3] : -src->i[3]; |
} |
static void |
micro_ineg(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->i[0] = -src->i[0]; |
dst->i[1] = -src->i[1]; |
dst->i[2] = -src->i[2]; |
dst->i[3] = -src->i[3]; |
} |
static void |
micro_lg2(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
#if FAST_MATH |
dst->f[0] = util_fast_log2(src->f[0]); |
dst->f[1] = util_fast_log2(src->f[1]); |
dst->f[2] = util_fast_log2(src->f[2]); |
dst->f[3] = util_fast_log2(src->f[3]); |
#else |
dst->f[0] = logf(src->f[0]) * 1.442695f; |
dst->f[1] = logf(src->f[1]) * 1.442695f; |
dst->f[2] = logf(src->f[2]) * 1.442695f; |
dst->f[3] = logf(src->f[3]) * 1.442695f; |
#endif |
} |
static void |
micro_lrp(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1, |
const union tgsi_exec_channel *src2) |
{ |
dst->f[0] = src0->f[0] * (src1->f[0] - src2->f[0]) + src2->f[0]; |
dst->f[1] = src0->f[1] * (src1->f[1] - src2->f[1]) + src2->f[1]; |
dst->f[2] = src0->f[2] * (src1->f[2] - src2->f[2]) + src2->f[2]; |
dst->f[3] = src0->f[3] * (src1->f[3] - src2->f[3]) + src2->f[3]; |
} |
static void |
micro_mad(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1, |
const union tgsi_exec_channel *src2) |
{ |
dst->f[0] = src0->f[0] * src1->f[0] + src2->f[0]; |
dst->f[1] = src0->f[1] * src1->f[1] + src2->f[1]; |
dst->f[2] = src0->f[2] * src1->f[2] + src2->f[2]; |
dst->f[3] = src0->f[3] * src1->f[3] + src2->f[3]; |
} |
static void |
micro_mov(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->u[0] = src->u[0]; |
dst->u[1] = src->u[1]; |
dst->u[2] = src->u[2]; |
dst->u[3] = src->u[3]; |
} |
static void |
micro_rcp(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
#if 0 /* for debugging */ |
assert(src->f[0] != 0.0f); |
assert(src->f[1] != 0.0f); |
assert(src->f[2] != 0.0f); |
assert(src->f[3] != 0.0f); |
#endif |
dst->f[0] = 1.0f / src->f[0]; |
dst->f[1] = 1.0f / src->f[1]; |
dst->f[2] = 1.0f / src->f[2]; |
dst->f[3] = 1.0f / src->f[3]; |
} |
static void |
micro_rnd(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = floorf(src->f[0] + 0.5f); |
dst->f[1] = floorf(src->f[1] + 0.5f); |
dst->f[2] = floorf(src->f[2] + 0.5f); |
dst->f[3] = floorf(src->f[3] + 0.5f); |
} |
static void |
micro_rsq(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
#if 0 /* for debugging */ |
assert(src->f[0] != 0.0f); |
assert(src->f[1] != 0.0f); |
assert(src->f[2] != 0.0f); |
assert(src->f[3] != 0.0f); |
#endif |
dst->f[0] = 1.0f / sqrtf(src->f[0]); |
dst->f[1] = 1.0f / sqrtf(src->f[1]); |
dst->f[2] = 1.0f / sqrtf(src->f[2]); |
dst->f[3] = 1.0f / sqrtf(src->f[3]); |
} |
static void |
micro_sqrt(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = sqrtf(src->f[0]); |
dst->f[1] = sqrtf(src->f[1]); |
dst->f[2] = sqrtf(src->f[2]); |
dst->f[3] = sqrtf(src->f[3]); |
} |
static void |
micro_seq(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->f[0] = src0->f[0] == src1->f[0] ? 1.0f : 0.0f; |
dst->f[1] = src0->f[1] == src1->f[1] ? 1.0f : 0.0f; |
dst->f[2] = src0->f[2] == src1->f[2] ? 1.0f : 0.0f; |
dst->f[3] = src0->f[3] == src1->f[3] ? 1.0f : 0.0f; |
} |
static void |
micro_sge(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->f[0] = src0->f[0] >= src1->f[0] ? 1.0f : 0.0f; |
dst->f[1] = src0->f[1] >= src1->f[1] ? 1.0f : 0.0f; |
dst->f[2] = src0->f[2] >= src1->f[2] ? 1.0f : 0.0f; |
dst->f[3] = src0->f[3] >= src1->f[3] ? 1.0f : 0.0f; |
} |
static void |
micro_sgn(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = src->f[0] < 0.0f ? -1.0f : src->f[0] > 0.0f ? 1.0f : 0.0f; |
dst->f[1] = src->f[1] < 0.0f ? -1.0f : src->f[1] > 0.0f ? 1.0f : 0.0f; |
dst->f[2] = src->f[2] < 0.0f ? -1.0f : src->f[2] > 0.0f ? 1.0f : 0.0f; |
dst->f[3] = src->f[3] < 0.0f ? -1.0f : src->f[3] > 0.0f ? 1.0f : 0.0f; |
} |
static void |
micro_isgn(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->i[0] = src->i[0] < 0 ? -1 : src->i[0] > 0 ? 1 : 0; |
dst->i[1] = src->i[1] < 0 ? -1 : src->i[1] > 0 ? 1 : 0; |
dst->i[2] = src->i[2] < 0 ? -1 : src->i[2] > 0 ? 1 : 0; |
dst->i[3] = src->i[3] < 0 ? -1 : src->i[3] > 0 ? 1 : 0; |
} |
static void |
micro_sgt(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->f[0] = src0->f[0] > src1->f[0] ? 1.0f : 0.0f; |
dst->f[1] = src0->f[1] > src1->f[1] ? 1.0f : 0.0f; |
dst->f[2] = src0->f[2] > src1->f[2] ? 1.0f : 0.0f; |
dst->f[3] = src0->f[3] > src1->f[3] ? 1.0f : 0.0f; |
} |
static void |
micro_sin(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = sinf(src->f[0]); |
dst->f[1] = sinf(src->f[1]); |
dst->f[2] = sinf(src->f[2]); |
dst->f[3] = sinf(src->f[3]); |
} |
static void |
micro_sle(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->f[0] = src0->f[0] <= src1->f[0] ? 1.0f : 0.0f; |
dst->f[1] = src0->f[1] <= src1->f[1] ? 1.0f : 0.0f; |
dst->f[2] = src0->f[2] <= src1->f[2] ? 1.0f : 0.0f; |
dst->f[3] = src0->f[3] <= src1->f[3] ? 1.0f : 0.0f; |
} |
static void |
micro_slt(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->f[0] = src0->f[0] < src1->f[0] ? 1.0f : 0.0f; |
dst->f[1] = src0->f[1] < src1->f[1] ? 1.0f : 0.0f; |
dst->f[2] = src0->f[2] < src1->f[2] ? 1.0f : 0.0f; |
dst->f[3] = src0->f[3] < src1->f[3] ? 1.0f : 0.0f; |
} |
static void |
micro_sne(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->f[0] = src0->f[0] != src1->f[0] ? 1.0f : 0.0f; |
dst->f[1] = src0->f[1] != src1->f[1] ? 1.0f : 0.0f; |
dst->f[2] = src0->f[2] != src1->f[2] ? 1.0f : 0.0f; |
dst->f[3] = src0->f[3] != src1->f[3] ? 1.0f : 0.0f; |
} |
static void |
micro_sfl(union tgsi_exec_channel *dst) |
{ |
dst->f[0] = 0.0f; |
dst->f[1] = 0.0f; |
dst->f[2] = 0.0f; |
dst->f[3] = 0.0f; |
} |
static void |
micro_str(union tgsi_exec_channel *dst) |
{ |
dst->f[0] = 1.0f; |
dst->f[1] = 1.0f; |
dst->f[2] = 1.0f; |
dst->f[3] = 1.0f; |
} |
static void |
micro_trunc(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = (float)(int)src->f[0]; |
dst->f[1] = (float)(int)src->f[1]; |
dst->f[2] = (float)(int)src->f[2]; |
dst->f[3] = (float)(int)src->f[3]; |
} |
enum tgsi_exec_datatype { |
TGSI_EXEC_DATA_FLOAT, |
TGSI_EXEC_DATA_INT, |
TGSI_EXEC_DATA_UINT |
}; |
/* |
* Shorthand locations of various utility registers (_I = Index, _C = Channel) |
*/ |
#define TEMP_KILMASK_I TGSI_EXEC_TEMP_KILMASK_I |
#define TEMP_KILMASK_C TGSI_EXEC_TEMP_KILMASK_C |
#define TEMP_OUTPUT_I TGSI_EXEC_TEMP_OUTPUT_I |
#define TEMP_OUTPUT_C TGSI_EXEC_TEMP_OUTPUT_C |
#define TEMP_PRIMITIVE_I TGSI_EXEC_TEMP_PRIMITIVE_I |
#define TEMP_PRIMITIVE_C TGSI_EXEC_TEMP_PRIMITIVE_C |
/** The execution mask depends on the conditional mask and the loop mask */ |
#define UPDATE_EXEC_MASK(MACH) \ |
MACH->ExecMask = MACH->CondMask & MACH->LoopMask & MACH->ContMask & MACH->Switch.mask & MACH->FuncMask |
static const union tgsi_exec_channel ZeroVec = |
{ { 0.0, 0.0, 0.0, 0.0 } }; |
static const union tgsi_exec_channel OneVec = { |
{1.0f, 1.0f, 1.0f, 1.0f} |
}; |
static const union tgsi_exec_channel P128Vec = { |
{128.0f, 128.0f, 128.0f, 128.0f} |
}; |
static const union tgsi_exec_channel M128Vec = { |
{-128.0f, -128.0f, -128.0f, -128.0f} |
}; |
/** |
* Assert that none of the float values in 'chan' are infinite or NaN. |
* NaN and Inf may occur normally during program execution and should |
* not lead to crashes, etc. But when debugging, it's helpful to catch |
* them. |
*/ |
static INLINE void |
check_inf_or_nan(const union tgsi_exec_channel *chan) |
{ |
assert(!util_is_inf_or_nan((chan)->f[0])); |
assert(!util_is_inf_or_nan((chan)->f[1])); |
assert(!util_is_inf_or_nan((chan)->f[2])); |
assert(!util_is_inf_or_nan((chan)->f[3])); |
} |
#ifdef DEBUG |
static void |
print_chan(const char *msg, const union tgsi_exec_channel *chan) |
{ |
debug_printf("%s = {%f, %f, %f, %f}\n", |
msg, chan->f[0], chan->f[1], chan->f[2], chan->f[3]); |
} |
#endif |
#ifdef DEBUG |
static void |
print_temp(const struct tgsi_exec_machine *mach, uint index) |
{ |
const struct tgsi_exec_vector *tmp = &mach->Temps[index]; |
int i; |
debug_printf("Temp[%u] =\n", index); |
for (i = 0; i < 4; i++) { |
debug_printf(" %c: { %f, %f, %f, %f }\n", |
"XYZW"[i], |
tmp->xyzw[i].f[0], |
tmp->xyzw[i].f[1], |
tmp->xyzw[i].f[2], |
tmp->xyzw[i].f[3]); |
} |
} |
#endif |
void |
tgsi_exec_set_constant_buffers(struct tgsi_exec_machine *mach, |
unsigned num_bufs, |
const void **bufs, |
const unsigned *buf_sizes) |
{ |
unsigned i; |
for (i = 0; i < num_bufs; i++) { |
mach->Consts[i] = bufs[i]; |
mach->ConstsSize[i] = buf_sizes[i]; |
} |
} |
/** |
* Check if there's a potential src/dst register data dependency when |
* using SOA execution. |
* Example: |
* MOV T, T.yxwz; |
* This would expand into: |
* MOV t0, t1; |
* MOV t1, t0; |
* MOV t2, t3; |
* MOV t3, t2; |
* The second instruction will have the wrong value for t0 if executed as-is. |
*/ |
boolean |
tgsi_check_soa_dependencies(const struct tgsi_full_instruction *inst) |
{ |
uint i, chan; |
uint writemask = inst->Dst[0].Register.WriteMask; |
if (writemask == TGSI_WRITEMASK_X || |
writemask == TGSI_WRITEMASK_Y || |
writemask == TGSI_WRITEMASK_Z || |
writemask == TGSI_WRITEMASK_W || |
writemask == TGSI_WRITEMASK_NONE) { |
/* no chance of data dependency */ |
return FALSE; |
} |
/* loop over src regs */ |
for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { |
if ((inst->Src[i].Register.File == |
inst->Dst[0].Register.File) && |
((inst->Src[i].Register.Index == |
inst->Dst[0].Register.Index) || |
inst->Src[i].Register.Indirect || |
inst->Dst[0].Register.Indirect)) { |
/* loop over dest channels */ |
uint channelsWritten = 0x0; |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
/* check if we're reading a channel that's been written */ |
uint swizzle = tgsi_util_get_full_src_register_swizzle(&inst->Src[i], chan); |
if (channelsWritten & (1 << swizzle)) { |
return TRUE; |
} |
channelsWritten |= (1 << chan); |
} |
} |
} |
} |
return FALSE; |
} |
/** |
* Initialize machine state by expanding tokens to full instructions, |
* allocating temporary storage, setting up constants, etc. |
* After this, we can call tgsi_exec_machine_run() many times. |
*/ |
void |
tgsi_exec_machine_bind_shader( |
struct tgsi_exec_machine *mach, |
const struct tgsi_token *tokens, |
struct tgsi_sampler *sampler) |
{ |
uint k; |
struct tgsi_parse_context parse; |
struct tgsi_full_instruction *instructions; |
struct tgsi_full_declaration *declarations; |
uint maxInstructions = 10, numInstructions = 0; |
uint maxDeclarations = 10, numDeclarations = 0; |
#if 0 |
tgsi_dump(tokens, 0); |
#endif |
util_init_math(); |
mach->Tokens = tokens; |
mach->Sampler = sampler; |
if (!tokens) { |
/* unbind and free all */ |
FREE(mach->Declarations); |
mach->Declarations = NULL; |
mach->NumDeclarations = 0; |
FREE(mach->Instructions); |
mach->Instructions = NULL; |
mach->NumInstructions = 0; |
return; |
} |
k = tgsi_parse_init (&parse, mach->Tokens); |
if (k != TGSI_PARSE_OK) { |
debug_printf( "Problem parsing!\n" ); |
return; |
} |
mach->Processor = parse.FullHeader.Processor.Processor; |
mach->ImmLimit = 0; |
mach->NumOutputs = 0; |
if (mach->Processor == TGSI_PROCESSOR_GEOMETRY && |
!mach->UsedGeometryShader) { |
struct tgsi_exec_vector *inputs; |
struct tgsi_exec_vector *outputs; |
inputs = align_malloc(sizeof(struct tgsi_exec_vector) * |
TGSI_MAX_PRIM_VERTICES * PIPE_MAX_ATTRIBS, |
16); |
if (!inputs) |
return; |
outputs = align_malloc(sizeof(struct tgsi_exec_vector) * |
TGSI_MAX_TOTAL_VERTICES, 16); |
if (!outputs) { |
align_free(inputs); |
return; |
} |
align_free(mach->Inputs); |
align_free(mach->Outputs); |
mach->Inputs = inputs; |
mach->Outputs = outputs; |
mach->UsedGeometryShader = TRUE; |
} |
declarations = (struct tgsi_full_declaration *) |
MALLOC( maxDeclarations * sizeof(struct tgsi_full_declaration) ); |
if (!declarations) { |
return; |
} |
instructions = (struct tgsi_full_instruction *) |
MALLOC( maxInstructions * sizeof(struct tgsi_full_instruction) ); |
if (!instructions) { |
FREE( declarations ); |
return; |
} |
while( !tgsi_parse_end_of_tokens( &parse ) ) { |
uint i; |
tgsi_parse_token( &parse ); |
switch( parse.FullToken.Token.Type ) { |
case TGSI_TOKEN_TYPE_DECLARATION: |
/* save expanded declaration */ |
if (numDeclarations == maxDeclarations) { |
declarations = REALLOC(declarations, |
maxDeclarations |
* sizeof(struct tgsi_full_declaration), |
(maxDeclarations + 10) |
* sizeof(struct tgsi_full_declaration)); |
maxDeclarations += 10; |
} |
if (parse.FullToken.FullDeclaration.Declaration.File == TGSI_FILE_OUTPUT) { |
unsigned reg; |
for (reg = parse.FullToken.FullDeclaration.Range.First; |
reg <= parse.FullToken.FullDeclaration.Range.Last; |
++reg) { |
++mach->NumOutputs; |
} |
} |
memcpy(declarations + numDeclarations, |
&parse.FullToken.FullDeclaration, |
sizeof(declarations[0])); |
numDeclarations++; |
break; |
case TGSI_TOKEN_TYPE_IMMEDIATE: |
{ |
uint size = parse.FullToken.FullImmediate.Immediate.NrTokens - 1; |
assert( size <= 4 ); |
assert( mach->ImmLimit + 1 <= TGSI_EXEC_NUM_IMMEDIATES ); |
for( i = 0; i < size; i++ ) { |
mach->Imms[mach->ImmLimit][i] = |
parse.FullToken.FullImmediate.u[i].Float; |
} |
mach->ImmLimit += 1; |
} |
break; |
case TGSI_TOKEN_TYPE_INSTRUCTION: |
/* save expanded instruction */ |
if (numInstructions == maxInstructions) { |
instructions = REALLOC(instructions, |
maxInstructions |
* sizeof(struct tgsi_full_instruction), |
(maxInstructions + 10) |
* sizeof(struct tgsi_full_instruction)); |
maxInstructions += 10; |
} |
memcpy(instructions + numInstructions, |
&parse.FullToken.FullInstruction, |
sizeof(instructions[0])); |
numInstructions++; |
break; |
case TGSI_TOKEN_TYPE_PROPERTY: |
break; |
default: |
assert( 0 ); |
} |
} |
tgsi_parse_free (&parse); |
FREE(mach->Declarations); |
mach->Declarations = declarations; |
mach->NumDeclarations = numDeclarations; |
FREE(mach->Instructions); |
mach->Instructions = instructions; |
mach->NumInstructions = numInstructions; |
} |
struct tgsi_exec_machine * |
tgsi_exec_machine_create( void ) |
{ |
struct tgsi_exec_machine *mach; |
uint i; |
mach = align_malloc( sizeof *mach, 16 ); |
if (!mach) |
goto fail; |
memset(mach, 0, sizeof(*mach)); |
mach->Addrs = &mach->Temps[TGSI_EXEC_TEMP_ADDR]; |
mach->MaxGeometryShaderOutputs = TGSI_MAX_TOTAL_VERTICES; |
mach->Predicates = &mach->Temps[TGSI_EXEC_TEMP_P0]; |
mach->Inputs = align_malloc(sizeof(struct tgsi_exec_vector) * PIPE_MAX_ATTRIBS, 16); |
mach->Outputs = align_malloc(sizeof(struct tgsi_exec_vector) * PIPE_MAX_ATTRIBS, 16); |
if (!mach->Inputs || !mach->Outputs) |
goto fail; |
/* Setup constants needed by the SSE2 executor. */ |
for( i = 0; i < 4; i++ ) { |
mach->Temps[TGSI_EXEC_TEMP_00000000_I].xyzw[TGSI_EXEC_TEMP_00000000_C].u[i] = 0x00000000; |
mach->Temps[TGSI_EXEC_TEMP_7FFFFFFF_I].xyzw[TGSI_EXEC_TEMP_7FFFFFFF_C].u[i] = 0x7FFFFFFF; |
mach->Temps[TGSI_EXEC_TEMP_80000000_I].xyzw[TGSI_EXEC_TEMP_80000000_C].u[i] = 0x80000000; |
mach->Temps[TGSI_EXEC_TEMP_FFFFFFFF_I].xyzw[TGSI_EXEC_TEMP_FFFFFFFF_C].u[i] = 0xFFFFFFFF; /* not used */ |
mach->Temps[TGSI_EXEC_TEMP_ONE_I].xyzw[TGSI_EXEC_TEMP_ONE_C].f[i] = 1.0f; |
mach->Temps[TGSI_EXEC_TEMP_TWO_I].xyzw[TGSI_EXEC_TEMP_TWO_C].f[i] = 2.0f; /* not used */ |
mach->Temps[TGSI_EXEC_TEMP_128_I].xyzw[TGSI_EXEC_TEMP_128_C].f[i] = 128.0f; |
mach->Temps[TGSI_EXEC_TEMP_MINUS_128_I].xyzw[TGSI_EXEC_TEMP_MINUS_128_C].f[i] = -128.0f; |
mach->Temps[TGSI_EXEC_TEMP_THREE_I].xyzw[TGSI_EXEC_TEMP_THREE_C].f[i] = 3.0f; |
mach->Temps[TGSI_EXEC_TEMP_HALF_I].xyzw[TGSI_EXEC_TEMP_HALF_C].f[i] = 0.5f; |
} |
#ifdef DEBUG |
/* silence warnings */ |
(void) print_chan; |
(void) print_temp; |
#endif |
return mach; |
fail: |
if (mach) { |
align_free(mach->Inputs); |
align_free(mach->Outputs); |
align_free(mach); |
} |
return NULL; |
} |
void |
tgsi_exec_machine_destroy(struct tgsi_exec_machine *mach) |
{ |
if (mach) { |
FREE(mach->Instructions); |
FREE(mach->Declarations); |
align_free(mach->Inputs); |
align_free(mach->Outputs); |
align_free(mach); |
} |
} |
static void |
micro_add(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->f[0] = src0->f[0] + src1->f[0]; |
dst->f[1] = src0->f[1] + src1->f[1]; |
dst->f[2] = src0->f[2] + src1->f[2]; |
dst->f[3] = src0->f[3] + src1->f[3]; |
} |
static void |
micro_div( |
union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1 ) |
{ |
if (src1->f[0] != 0) { |
dst->f[0] = src0->f[0] / src1->f[0]; |
} |
if (src1->f[1] != 0) { |
dst->f[1] = src0->f[1] / src1->f[1]; |
} |
if (src1->f[2] != 0) { |
dst->f[2] = src0->f[2] / src1->f[2]; |
} |
if (src1->f[3] != 0) { |
dst->f[3] = src0->f[3] / src1->f[3]; |
} |
} |
static void |
micro_rcc(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
uint i; |
for (i = 0; i < 4; i++) { |
float recip = 1.0f / src->f[i]; |
if (recip > 0.0f) { |
if (recip > 1.884467e+019f) { |
dst->f[i] = 1.884467e+019f; |
} |
else if (recip < 5.42101e-020f) { |
dst->f[i] = 5.42101e-020f; |
} |
else { |
dst->f[i] = recip; |
} |
} |
else { |
if (recip < -1.884467e+019f) { |
dst->f[i] = -1.884467e+019f; |
} |
else if (recip > -5.42101e-020f) { |
dst->f[i] = -5.42101e-020f; |
} |
else { |
dst->f[i] = recip; |
} |
} |
} |
} |
static void |
micro_lt( |
union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1, |
const union tgsi_exec_channel *src2, |
const union tgsi_exec_channel *src3 ) |
{ |
dst->f[0] = src0->f[0] < src1->f[0] ? src2->f[0] : src3->f[0]; |
dst->f[1] = src0->f[1] < src1->f[1] ? src2->f[1] : src3->f[1]; |
dst->f[2] = src0->f[2] < src1->f[2] ? src2->f[2] : src3->f[2]; |
dst->f[3] = src0->f[3] < src1->f[3] ? src2->f[3] : src3->f[3]; |
} |
static void |
micro_max(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->f[0] = src0->f[0] > src1->f[0] ? src0->f[0] : src1->f[0]; |
dst->f[1] = src0->f[1] > src1->f[1] ? src0->f[1] : src1->f[1]; |
dst->f[2] = src0->f[2] > src1->f[2] ? src0->f[2] : src1->f[2]; |
dst->f[3] = src0->f[3] > src1->f[3] ? src0->f[3] : src1->f[3]; |
} |
static void |
micro_min(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->f[0] = src0->f[0] < src1->f[0] ? src0->f[0] : src1->f[0]; |
dst->f[1] = src0->f[1] < src1->f[1] ? src0->f[1] : src1->f[1]; |
dst->f[2] = src0->f[2] < src1->f[2] ? src0->f[2] : src1->f[2]; |
dst->f[3] = src0->f[3] < src1->f[3] ? src0->f[3] : src1->f[3]; |
} |
static void |
micro_mul(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->f[0] = src0->f[0] * src1->f[0]; |
dst->f[1] = src0->f[1] * src1->f[1]; |
dst->f[2] = src0->f[2] * src1->f[2]; |
dst->f[3] = src0->f[3] * src1->f[3]; |
} |
static void |
micro_neg( |
union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src ) |
{ |
dst->f[0] = -src->f[0]; |
dst->f[1] = -src->f[1]; |
dst->f[2] = -src->f[2]; |
dst->f[3] = -src->f[3]; |
} |
static void |
micro_pow( |
union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1 ) |
{ |
#if FAST_MATH |
dst->f[0] = util_fast_pow( src0->f[0], src1->f[0] ); |
dst->f[1] = util_fast_pow( src0->f[1], src1->f[1] ); |
dst->f[2] = util_fast_pow( src0->f[2], src1->f[2] ); |
dst->f[3] = util_fast_pow( src0->f[3], src1->f[3] ); |
#else |
dst->f[0] = powf( src0->f[0], src1->f[0] ); |
dst->f[1] = powf( src0->f[1], src1->f[1] ); |
dst->f[2] = powf( src0->f[2], src1->f[2] ); |
dst->f[3] = powf( src0->f[3], src1->f[3] ); |
#endif |
} |
static void |
micro_sub(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->f[0] = src0->f[0] - src1->f[0]; |
dst->f[1] = src0->f[1] - src1->f[1]; |
dst->f[2] = src0->f[2] - src1->f[2]; |
dst->f[3] = src0->f[3] - src1->f[3]; |
} |
static void |
fetch_src_file_channel(const struct tgsi_exec_machine *mach, |
const uint chan_index, |
const uint file, |
const uint swizzle, |
const union tgsi_exec_channel *index, |
const union tgsi_exec_channel *index2D, |
union tgsi_exec_channel *chan) |
{ |
uint i; |
assert(swizzle < 4); |
switch (file) { |
case TGSI_FILE_CONSTANT: |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
assert(index2D->i[i] >= 0 && index2D->i[i] < PIPE_MAX_CONSTANT_BUFFERS); |
assert(mach->Consts[index2D->i[i]]); |
if (index->i[i] < 0) { |
chan->u[i] = 0; |
} else { |
/* NOTE: copying the const value as a uint instead of float */ |
const uint constbuf = index2D->i[i]; |
const uint *buf = (const uint *)mach->Consts[constbuf]; |
const int pos = index->i[i] * 4 + swizzle; |
/* const buffer bounds check */ |
if (pos < 0 || pos >= (int) mach->ConstsSize[constbuf]) { |
if (0) { |
/* Debug: print warning */ |
static int count = 0; |
if (count++ < 100) |
debug_printf("TGSI Exec: const buffer index %d" |
" out of bounds\n", pos); |
} |
chan->u[i] = 0; |
} |
else |
chan->u[i] = buf[pos]; |
} |
} |
break; |
case TGSI_FILE_INPUT: |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
/* |
if (TGSI_PROCESSOR_GEOMETRY == mach->Processor) { |
debug_printf("Fetching Input[%d] (2d=%d, 1d=%d)\n", |
index2D->i[i] * TGSI_EXEC_MAX_INPUT_ATTRIBS + index->i[i], |
index2D->i[i], index->i[i]); |
}*/ |
int pos = index2D->i[i] * TGSI_EXEC_MAX_INPUT_ATTRIBS + index->i[i]; |
assert(pos >= 0); |
assert(pos < TGSI_MAX_PRIM_VERTICES * PIPE_MAX_ATTRIBS); |
chan->u[i] = mach->Inputs[pos].xyzw[swizzle].u[i]; |
} |
break; |
case TGSI_FILE_SYSTEM_VALUE: |
/* XXX no swizzling at this point. Will be needed if we put |
* gl_FragCoord, for example, in a sys value register. |
*/ |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
chan->u[i] = mach->SystemValue[index->i[i]].u[i]; |
} |
break; |
case TGSI_FILE_TEMPORARY: |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
assert(index->i[i] < TGSI_EXEC_NUM_TEMPS); |
assert(index2D->i[i] == 0); |
chan->u[i] = mach->Temps[index->i[i]].xyzw[swizzle].u[i]; |
} |
break; |
case TGSI_FILE_IMMEDIATE: |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
assert(index->i[i] >= 0 && index->i[i] < (int)mach->ImmLimit); |
assert(index2D->i[i] == 0); |
chan->f[i] = mach->Imms[index->i[i]][swizzle]; |
} |
break; |
case TGSI_FILE_ADDRESS: |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
assert(index->i[i] >= 0); |
assert(index2D->i[i] == 0); |
chan->u[i] = mach->Addrs[index->i[i]].xyzw[swizzle].u[i]; |
} |
break; |
case TGSI_FILE_PREDICATE: |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
assert(index->i[i] >= 0 && index->i[i] < TGSI_EXEC_NUM_PREDS); |
assert(index2D->i[i] == 0); |
chan->u[i] = mach->Predicates[0].xyzw[swizzle].u[i]; |
} |
break; |
case TGSI_FILE_OUTPUT: |
/* vertex/fragment output vars can be read too */ |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
assert(index->i[i] >= 0); |
assert(index2D->i[i] == 0); |
chan->u[i] = mach->Outputs[index->i[i]].xyzw[swizzle].u[i]; |
} |
break; |
default: |
assert(0); |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
chan->u[i] = 0; |
} |
} |
} |
static void |
fetch_source(const struct tgsi_exec_machine *mach, |
union tgsi_exec_channel *chan, |
const struct tgsi_full_src_register *reg, |
const uint chan_index, |
enum tgsi_exec_datatype src_datatype) |
{ |
union tgsi_exec_channel index; |
union tgsi_exec_channel index2D; |
uint swizzle; |
/* We start with a direct index into a register file. |
* |
* file[1], |
* where: |
* file = Register.File |
* [1] = Register.Index |
*/ |
index.i[0] = |
index.i[1] = |
index.i[2] = |
index.i[3] = reg->Register.Index; |
/* There is an extra source register that indirectly subscripts |
* a register file. The direct index now becomes an offset |
* that is being added to the indirect register. |
* |
* file[ind[2].x+1], |
* where: |
* ind = Indirect.File |
* [2] = Indirect.Index |
* .x = Indirect.SwizzleX |
*/ |
if (reg->Register.Indirect) { |
union tgsi_exec_channel index2; |
union tgsi_exec_channel indir_index; |
const uint execmask = mach->ExecMask; |
uint i; |
/* which address register (always zero now) */ |
index2.i[0] = |
index2.i[1] = |
index2.i[2] = |
index2.i[3] = reg->Indirect.Index; |
/* get current value of address register[swizzle] */ |
swizzle = reg->Indirect.Swizzle; |
fetch_src_file_channel(mach, |
chan_index, |
reg->Indirect.File, |
swizzle, |
&index2, |
&ZeroVec, |
&indir_index); |
/* add value of address register to the offset */ |
index.i[0] += indir_index.i[0]; |
index.i[1] += indir_index.i[1]; |
index.i[2] += indir_index.i[2]; |
index.i[3] += indir_index.i[3]; |
/* for disabled execution channels, zero-out the index to |
* avoid using a potential garbage value. |
*/ |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
if ((execmask & (1 << i)) == 0) |
index.i[i] = 0; |
} |
} |
/* There is an extra source register that is a second |
* subscript to a register file. Effectively it means that |
* the register file is actually a 2D array of registers. |
* |
* file[3][1], |
* where: |
* [3] = Dimension.Index |
*/ |
if (reg->Register.Dimension) { |
index2D.i[0] = |
index2D.i[1] = |
index2D.i[2] = |
index2D.i[3] = reg->Dimension.Index; |
/* Again, the second subscript index can be addressed indirectly |
* identically to the first one. |
* Nothing stops us from indirectly addressing the indirect register, |
* but there is no need for that, so we won't exercise it. |
* |
* file[ind[4].y+3][1], |
* where: |
* ind = DimIndirect.File |
* [4] = DimIndirect.Index |
* .y = DimIndirect.SwizzleX |
*/ |
if (reg->Dimension.Indirect) { |
union tgsi_exec_channel index2; |
union tgsi_exec_channel indir_index; |
const uint execmask = mach->ExecMask; |
uint i; |
index2.i[0] = |
index2.i[1] = |
index2.i[2] = |
index2.i[3] = reg->DimIndirect.Index; |
swizzle = reg->DimIndirect.Swizzle; |
fetch_src_file_channel(mach, |
chan_index, |
reg->DimIndirect.File, |
swizzle, |
&index2, |
&ZeroVec, |
&indir_index); |
index2D.i[0] += indir_index.i[0]; |
index2D.i[1] += indir_index.i[1]; |
index2D.i[2] += indir_index.i[2]; |
index2D.i[3] += indir_index.i[3]; |
/* for disabled execution channels, zero-out the index to |
* avoid using a potential garbage value. |
*/ |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
if ((execmask & (1 << i)) == 0) { |
index2D.i[i] = 0; |
} |
} |
} |
/* If by any chance there was a need for a 3D array of register |
* files, we would have to check whether Dimension is followed |
* by a dimension register and continue the saga. |
*/ |
} else { |
index2D.i[0] = |
index2D.i[1] = |
index2D.i[2] = |
index2D.i[3] = 0; |
} |
swizzle = tgsi_util_get_full_src_register_swizzle( reg, chan_index ); |
fetch_src_file_channel(mach, |
chan_index, |
reg->Register.File, |
swizzle, |
&index, |
&index2D, |
chan); |
if (reg->Register.Absolute) { |
if (src_datatype == TGSI_EXEC_DATA_FLOAT) { |
micro_abs(chan, chan); |
} else { |
micro_iabs(chan, chan); |
} |
} |
if (reg->Register.Negate) { |
if (src_datatype == TGSI_EXEC_DATA_FLOAT) { |
micro_neg(chan, chan); |
} else { |
micro_ineg(chan, chan); |
} |
} |
} |
static void |
store_dest(struct tgsi_exec_machine *mach, |
const union tgsi_exec_channel *chan, |
const struct tgsi_full_dst_register *reg, |
const struct tgsi_full_instruction *inst, |
uint chan_index, |
enum tgsi_exec_datatype dst_datatype) |
{ |
uint i; |
union tgsi_exec_channel null; |
union tgsi_exec_channel *dst; |
union tgsi_exec_channel index2D; |
uint execmask = mach->ExecMask; |
int offset = 0; /* indirection offset */ |
int index; |
/* for debugging */ |
if (0 && dst_datatype == TGSI_EXEC_DATA_FLOAT) { |
check_inf_or_nan(chan); |
} |
/* There is an extra source register that indirectly subscripts |
* a register file. The direct index now becomes an offset |
* that is being added to the indirect register. |
* |
* file[ind[2].x+1], |
* where: |
* ind = Indirect.File |
* [2] = Indirect.Index |
* .x = Indirect.SwizzleX |
*/ |
if (reg->Register.Indirect) { |
union tgsi_exec_channel index; |
union tgsi_exec_channel indir_index; |
uint swizzle; |
/* which address register (always zero for now) */ |
index.i[0] = |
index.i[1] = |
index.i[2] = |
index.i[3] = reg->Indirect.Index; |
/* get current value of address register[swizzle] */ |
swizzle = reg->Indirect.Swizzle; |
/* fetch values from the address/indirection register */ |
fetch_src_file_channel(mach, |
chan_index, |
reg->Indirect.File, |
swizzle, |
&index, |
&ZeroVec, |
&indir_index); |
/* save indirection offset */ |
offset = indir_index.i[0]; |
} |
/* There is an extra source register that is a second |
* subscript to a register file. Effectively it means that |
* the register file is actually a 2D array of registers. |
* |
* file[3][1], |
* where: |
* [3] = Dimension.Index |
*/ |
if (reg->Register.Dimension) { |
index2D.i[0] = |
index2D.i[1] = |
index2D.i[2] = |
index2D.i[3] = reg->Dimension.Index; |
/* Again, the second subscript index can be addressed indirectly |
* identically to the first one. |
* Nothing stops us from indirectly addressing the indirect register, |
* but there is no need for that, so we won't exercise it. |
* |
* file[ind[4].y+3][1], |
* where: |
* ind = DimIndirect.File |
* [4] = DimIndirect.Index |
* .y = DimIndirect.SwizzleX |
*/ |
if (reg->Dimension.Indirect) { |
union tgsi_exec_channel index2; |
union tgsi_exec_channel indir_index; |
const uint execmask = mach->ExecMask; |
unsigned swizzle; |
uint i; |
index2.i[0] = |
index2.i[1] = |
index2.i[2] = |
index2.i[3] = reg->DimIndirect.Index; |
swizzle = reg->DimIndirect.Swizzle; |
fetch_src_file_channel(mach, |
chan_index, |
reg->DimIndirect.File, |
swizzle, |
&index2, |
&ZeroVec, |
&indir_index); |
index2D.i[0] += indir_index.i[0]; |
index2D.i[1] += indir_index.i[1]; |
index2D.i[2] += indir_index.i[2]; |
index2D.i[3] += indir_index.i[3]; |
/* for disabled execution channels, zero-out the index to |
* avoid using a potential garbage value. |
*/ |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
if ((execmask & (1 << i)) == 0) { |
index2D.i[i] = 0; |
} |
} |
} |
/* If by any chance there was a need for a 3D array of register |
* files, we would have to check whether Dimension is followed |
* by a dimension register and continue the saga. |
*/ |
} else { |
index2D.i[0] = |
index2D.i[1] = |
index2D.i[2] = |
index2D.i[3] = 0; |
} |
switch (reg->Register.File) { |
case TGSI_FILE_NULL: |
dst = &null; |
break; |
case TGSI_FILE_OUTPUT: |
index = mach->Temps[TEMP_OUTPUT_I].xyzw[TEMP_OUTPUT_C].u[0] |
+ reg->Register.Index; |
dst = &mach->Outputs[offset + index].xyzw[chan_index]; |
#if 0 |
debug_printf("NumOutputs = %d, TEMP_O_C/I = %d, redindex = %d\n", |
mach->NumOutputs, mach->Temps[TEMP_OUTPUT_I].xyzw[TEMP_OUTPUT_C].u[0], |
reg->Register.Index); |
if (TGSI_PROCESSOR_GEOMETRY == mach->Processor) { |
debug_printf("STORING OUT[%d] mask(%d), = (", offset + index, execmask); |
for (i = 0; i < TGSI_QUAD_SIZE; i++) |
if (execmask & (1 << i)) |
debug_printf("%f, ", chan->f[i]); |
debug_printf(")\n"); |
} |
#endif |
break; |
case TGSI_FILE_TEMPORARY: |
index = reg->Register.Index; |
assert( index < TGSI_EXEC_NUM_TEMPS ); |
dst = &mach->Temps[offset + index].xyzw[chan_index]; |
break; |
case TGSI_FILE_ADDRESS: |
index = reg->Register.Index; |
dst = &mach->Addrs[index].xyzw[chan_index]; |
break; |
case TGSI_FILE_PREDICATE: |
index = reg->Register.Index; |
assert(index < TGSI_EXEC_NUM_PREDS); |
dst = &mach->Predicates[index].xyzw[chan_index]; |
break; |
default: |
assert( 0 ); |
return; |
} |
if (inst->Instruction.Predicate) { |
uint swizzle; |
union tgsi_exec_channel *pred; |
switch (chan_index) { |
case TGSI_CHAN_X: |
swizzle = inst->Predicate.SwizzleX; |
break; |
case TGSI_CHAN_Y: |
swizzle = inst->Predicate.SwizzleY; |
break; |
case TGSI_CHAN_Z: |
swizzle = inst->Predicate.SwizzleZ; |
break; |
case TGSI_CHAN_W: |
swizzle = inst->Predicate.SwizzleW; |
break; |
default: |
assert(0); |
return; |
} |
assert(inst->Predicate.Index == 0); |
pred = &mach->Predicates[inst->Predicate.Index].xyzw[swizzle]; |
if (inst->Predicate.Negate) { |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
if (pred->u[i]) { |
execmask &= ~(1 << i); |
} |
} |
} else { |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
if (!pred->u[i]) { |
execmask &= ~(1 << i); |
} |
} |
} |
} |
switch (inst->Instruction.Saturate) { |
case TGSI_SAT_NONE: |
for (i = 0; i < TGSI_QUAD_SIZE; i++) |
if (execmask & (1 << i)) |
dst->i[i] = chan->i[i]; |
break; |
case TGSI_SAT_ZERO_ONE: |
for (i = 0; i < TGSI_QUAD_SIZE; i++) |
if (execmask & (1 << i)) { |
if (chan->f[i] < 0.0f) |
dst->f[i] = 0.0f; |
else if (chan->f[i] > 1.0f) |
dst->f[i] = 1.0f; |
else |
dst->i[i] = chan->i[i]; |
} |
break; |
case TGSI_SAT_MINUS_PLUS_ONE: |
for (i = 0; i < TGSI_QUAD_SIZE; i++) |
if (execmask & (1 << i)) { |
if (chan->f[i] < -1.0f) |
dst->f[i] = -1.0f; |
else if (chan->f[i] > 1.0f) |
dst->f[i] = 1.0f; |
else |
dst->i[i] = chan->i[i]; |
} |
break; |
default: |
assert( 0 ); |
} |
} |
#define FETCH(VAL,INDEX,CHAN)\ |
fetch_source(mach, VAL, &inst->Src[INDEX], CHAN, TGSI_EXEC_DATA_FLOAT) |
#define IFETCH(VAL,INDEX,CHAN)\ |
fetch_source(mach, VAL, &inst->Src[INDEX], CHAN, TGSI_EXEC_DATA_INT) |
/** |
* Execute ARB-style KIL which is predicated by a src register. |
* Kill fragment if any of the four values is less than zero. |
*/ |
static void |
exec_kill_if(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
uint uniquemask; |
uint chan_index; |
uint kilmask = 0; /* bit 0 = pixel 0, bit 1 = pixel 1, etc */ |
union tgsi_exec_channel r[1]; |
/* This mask stores component bits that were already tested. */ |
uniquemask = 0; |
for (chan_index = 0; chan_index < 4; chan_index++) |
{ |
uint swizzle; |
uint i; |
/* unswizzle channel */ |
swizzle = tgsi_util_get_full_src_register_swizzle ( |
&inst->Src[0], |
chan_index); |
/* check if the component has not been already tested */ |
if (uniquemask & (1 << swizzle)) |
continue; |
uniquemask |= 1 << swizzle; |
FETCH(&r[0], 0, chan_index); |
for (i = 0; i < 4; i++) |
if (r[0].f[i] < 0.0f) |
kilmask |= 1 << i; |
} |
mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0] |= kilmask; |
} |
/** |
* Unconditional fragment kill/discard. |
*/ |
static void |
exec_kill(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
uint kilmask; /* bit 0 = pixel 0, bit 1 = pixel 1, etc */ |
/* kill fragment for all fragments currently executing */ |
kilmask = mach->ExecMask; |
mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0] |= kilmask; |
} |
static void |
emit_vertex(struct tgsi_exec_machine *mach) |
{ |
/* FIXME: check for exec mask correctly |
unsigned i; |
for (i = 0; i < TGSI_QUAD_SIZE; ++i) { |
if ((mach->ExecMask & (1 << i))) |
*/ |
if (mach->ExecMask) { |
mach->Temps[TEMP_OUTPUT_I].xyzw[TEMP_OUTPUT_C].u[0] += mach->NumOutputs; |
mach->Primitives[mach->Temps[TEMP_PRIMITIVE_I].xyzw[TEMP_PRIMITIVE_C].u[0]]++; |
} |
} |
static void |
emit_primitive(struct tgsi_exec_machine *mach) |
{ |
unsigned *prim_count = &mach->Temps[TEMP_PRIMITIVE_I].xyzw[TEMP_PRIMITIVE_C].u[0]; |
/* FIXME: check for exec mask correctly |
unsigned i; |
for (i = 0; i < TGSI_QUAD_SIZE; ++i) { |
if ((mach->ExecMask & (1 << i))) |
*/ |
if (mach->ExecMask) { |
++(*prim_count); |
debug_assert((*prim_count * mach->NumOutputs) < mach->MaxGeometryShaderOutputs); |
mach->Primitives[*prim_count] = 0; |
} |
} |
static void |
conditional_emit_primitive(struct tgsi_exec_machine *mach) |
{ |
if (TGSI_PROCESSOR_GEOMETRY == mach->Processor) { |
int emitted_verts = |
mach->Primitives[mach->Temps[TEMP_PRIMITIVE_I].xyzw[TEMP_PRIMITIVE_C].u[0]]; |
if (emitted_verts) { |
emit_primitive(mach); |
} |
} |
} |
/* |
* Fetch four texture samples using STR texture coordinates. |
*/ |
static void |
fetch_texel( struct tgsi_sampler *sampler, |
const unsigned sview_idx, |
const unsigned sampler_idx, |
const union tgsi_exec_channel *s, |
const union tgsi_exec_channel *t, |
const union tgsi_exec_channel *p, |
const union tgsi_exec_channel *c0, |
const union tgsi_exec_channel *c1, |
float derivs[3][2][TGSI_QUAD_SIZE], |
const int8_t offset[3], |
enum tgsi_sampler_control control, |
union tgsi_exec_channel *r, |
union tgsi_exec_channel *g, |
union tgsi_exec_channel *b, |
union tgsi_exec_channel *a ) |
{ |
uint j; |
float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; |
/* FIXME: handle explicit derivs, offsets */ |
sampler->get_samples(sampler, sview_idx, sampler_idx, |
s->f, t->f, p->f, c0->f, c1->f, derivs, offset, control, rgba); |
for (j = 0; j < 4; j++) { |
r->f[j] = rgba[0][j]; |
g->f[j] = rgba[1][j]; |
b->f[j] = rgba[2][j]; |
a->f[j] = rgba[3][j]; |
} |
} |
#define TEX_MODIFIER_NONE 0 |
#define TEX_MODIFIER_PROJECTED 1 |
#define TEX_MODIFIER_LOD_BIAS 2 |
#define TEX_MODIFIER_EXPLICIT_LOD 3 |
#define TEX_MODIFIER_LEVEL_ZERO 4 |
/* |
* Fetch all 3 (for s,t,r coords) texel offsets, put them into int array. |
*/ |
static void |
fetch_texel_offsets(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst, |
int8_t offsets[3]) |
{ |
if (inst->Texture.NumOffsets == 1) { |
union tgsi_exec_channel index; |
union tgsi_exec_channel offset[3]; |
index.i[0] = index.i[1] = index.i[2] = index.i[3] = inst->TexOffsets[0].Index; |
fetch_src_file_channel(mach, 0, inst->TexOffsets[0].File, |
inst->TexOffsets[0].SwizzleX, &index, &ZeroVec, &offset[0]); |
fetch_src_file_channel(mach, 0, inst->TexOffsets[0].File, |
inst->TexOffsets[0].SwizzleY, &index, &ZeroVec, &offset[1]); |
fetch_src_file_channel(mach, 0, inst->TexOffsets[0].File, |
inst->TexOffsets[0].SwizzleZ, &index, &ZeroVec, &offset[2]); |
offsets[0] = offset[0].i[0]; |
offsets[1] = offset[1].i[0]; |
offsets[2] = offset[2].i[0]; |
} else { |
assert(inst->Texture.NumOffsets == 0); |
offsets[0] = offsets[1] = offsets[2] = 0; |
} |
} |
/* |
* Fetch dx and dy values for one channel (s, t or r). |
* Put dx values into one float array, dy values into another. |
*/ |
static void |
fetch_assign_deriv_channel(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst, |
unsigned regdsrcx, |
unsigned chan, |
float derivs[2][TGSI_QUAD_SIZE]) |
{ |
union tgsi_exec_channel d; |
FETCH(&d, regdsrcx, chan); |
derivs[0][0] = d.f[0]; |
derivs[0][1] = d.f[1]; |
derivs[0][2] = d.f[2]; |
derivs[0][3] = d.f[3]; |
FETCH(&d, regdsrcx + 1, chan); |
derivs[1][0] = d.f[0]; |
derivs[1][1] = d.f[1]; |
derivs[1][2] = d.f[2]; |
derivs[1][3] = d.f[3]; |
} |
/* |
* execute a texture instruction. |
* |
* modifier is used to control the channel routing for the\ |
* instruction variants like proj, lod, and texture with lod bias. |
* sampler indicates which src register the sampler is contained in. |
*/ |
static void |
exec_tex(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst, |
uint modifier, uint sampler) |
{ |
const uint unit = inst->Src[sampler].Register.Index; |
const union tgsi_exec_channel *args[5], *proj = NULL; |
union tgsi_exec_channel r[5]; |
enum tgsi_sampler_control control = tgsi_sampler_lod_none; |
uint chan; |
int8_t offsets[3]; |
int dim, shadow_ref, i; |
/* always fetch all 3 offsets, overkill but keeps code simple */ |
fetch_texel_offsets(mach, inst, offsets); |
assert(modifier != TEX_MODIFIER_LEVEL_ZERO); |
assert(inst->Texture.Texture != TGSI_TEXTURE_BUFFER); |
dim = tgsi_util_get_texture_coord_dim(inst->Texture.Texture, &shadow_ref); |
assert(dim <= 4); |
if (shadow_ref >= 0) |
assert(shadow_ref >= dim && shadow_ref < Elements(args)); |
/* fetch modifier to the last argument */ |
if (modifier != TEX_MODIFIER_NONE) { |
const int last = Elements(args) - 1; |
/* fetch modifier from src0.w or src1.x */ |
if (sampler == 1) { |
assert(dim <= TGSI_CHAN_W && shadow_ref != TGSI_CHAN_W); |
FETCH(&r[last], 0, TGSI_CHAN_W); |
} |
else { |
assert(shadow_ref != 4); |
FETCH(&r[last], 1, TGSI_CHAN_X); |
} |
if (modifier != TEX_MODIFIER_PROJECTED) { |
args[last] = &r[last]; |
} |
else { |
proj = &r[last]; |
args[last] = &ZeroVec; |
} |
/* point unused arguments to zero vector */ |
for (i = dim; i < last; i++) |
args[i] = &ZeroVec; |
if (modifier == TEX_MODIFIER_EXPLICIT_LOD) |
control = tgsi_sampler_lod_explicit; |
else if (modifier == TEX_MODIFIER_LOD_BIAS) |
control = tgsi_sampler_lod_bias; |
} |
else { |
for (i = dim; i < Elements(args); i++) |
args[i] = &ZeroVec; |
} |
/* fetch coordinates */ |
for (i = 0; i < dim; i++) { |
FETCH(&r[i], 0, TGSI_CHAN_X + i); |
if (proj) |
micro_div(&r[i], &r[i], proj); |
args[i] = &r[i]; |
} |
/* fetch reference value */ |
if (shadow_ref >= 0) { |
FETCH(&r[shadow_ref], shadow_ref / 4, TGSI_CHAN_X + (shadow_ref % 4)); |
if (proj) |
micro_div(&r[shadow_ref], &r[shadow_ref], proj); |
args[shadow_ref] = &r[shadow_ref]; |
} |
fetch_texel(mach->Sampler, unit, unit, |
args[0], args[1], args[2], args[3], args[4], |
NULL, offsets, control, |
&r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ |
#if 0 |
debug_printf("fetch r: %g %g %g %g\n", |
r[0].f[0], r[0].f[1], r[0].f[2], r[0].f[3]); |
debug_printf("fetch g: %g %g %g %g\n", |
r[1].f[0], r[1].f[1], r[1].f[2], r[1].f[3]); |
debug_printf("fetch b: %g %g %g %g\n", |
r[2].f[0], r[2].f[1], r[2].f[2], r[2].f[3]); |
debug_printf("fetch a: %g %g %g %g\n", |
r[3].f[0], r[3].f[1], r[3].f[2], r[3].f[3]); |
#endif |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &r[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); |
} |
} |
} |
static void |
exec_txd(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
const uint unit = inst->Src[3].Register.Index; |
union tgsi_exec_channel r[4]; |
float derivs[3][2][TGSI_QUAD_SIZE]; |
uint chan; |
int8_t offsets[3]; |
/* always fetch all 3 offsets, overkill but keeps code simple */ |
fetch_texel_offsets(mach, inst, offsets); |
switch (inst->Texture.Texture) { |
case TGSI_TEXTURE_1D: |
FETCH(&r[0], 0, TGSI_CHAN_X); |
fetch_assign_deriv_channel(mach, inst, 1, TGSI_CHAN_X, derivs[0]); |
fetch_texel(mach->Sampler, unit, unit, |
&r[0], &ZeroVec, &ZeroVec, &ZeroVec, &ZeroVec, /* S, T, P, C, LOD */ |
derivs, offsets, tgsi_sampler_derivs_explicit, |
&r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ |
break; |
case TGSI_TEXTURE_SHADOW1D: |
case TGSI_TEXTURE_1D_ARRAY: |
case TGSI_TEXTURE_SHADOW1D_ARRAY: |
/* SHADOW1D/1D_ARRAY would not need Y/Z respectively, but don't bother */ |
FETCH(&r[0], 0, TGSI_CHAN_X); |
FETCH(&r[1], 0, TGSI_CHAN_Y); |
FETCH(&r[2], 0, TGSI_CHAN_Z); |
fetch_assign_deriv_channel(mach, inst, 1, TGSI_CHAN_X, derivs[0]); |
fetch_texel(mach->Sampler, unit, unit, |
&r[0], &r[1], &r[2], &ZeroVec, &ZeroVec, /* S, T, P, C, LOD */ |
derivs, offsets, tgsi_sampler_derivs_explicit, |
&r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ |
break; |
case TGSI_TEXTURE_2D: |
case TGSI_TEXTURE_RECT: |
FETCH(&r[0], 0, TGSI_CHAN_X); |
FETCH(&r[1], 0, TGSI_CHAN_Y); |
fetch_assign_deriv_channel(mach, inst, 1, TGSI_CHAN_X, derivs[0]); |
fetch_assign_deriv_channel(mach, inst, 1, TGSI_CHAN_Y, derivs[1]); |
fetch_texel(mach->Sampler, unit, unit, |
&r[0], &r[1], &ZeroVec, &ZeroVec, &ZeroVec, /* S, T, P, C, LOD */ |
derivs, offsets, tgsi_sampler_derivs_explicit, |
&r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ |
break; |
case TGSI_TEXTURE_SHADOW2D: |
case TGSI_TEXTURE_SHADOWRECT: |
case TGSI_TEXTURE_2D_ARRAY: |
case TGSI_TEXTURE_SHADOW2D_ARRAY: |
/* only SHADOW2D_ARRAY actually needs W */ |
FETCH(&r[0], 0, TGSI_CHAN_X); |
FETCH(&r[1], 0, TGSI_CHAN_Y); |
FETCH(&r[2], 0, TGSI_CHAN_Z); |
FETCH(&r[3], 0, TGSI_CHAN_W); |
fetch_assign_deriv_channel(mach, inst, 1, TGSI_CHAN_X, derivs[0]); |
fetch_assign_deriv_channel(mach, inst, 1, TGSI_CHAN_Y, derivs[1]); |
fetch_texel(mach->Sampler, unit, unit, |
&r[0], &r[1], &r[2], &r[3], &ZeroVec, /* inputs */ |
derivs, offsets, tgsi_sampler_derivs_explicit, |
&r[0], &r[1], &r[2], &r[3]); /* outputs */ |
break; |
case TGSI_TEXTURE_3D: |
case TGSI_TEXTURE_CUBE: |
case TGSI_TEXTURE_CUBE_ARRAY: |
/* only TEXTURE_CUBE_ARRAY actually needs W */ |
FETCH(&r[0], 0, TGSI_CHAN_X); |
FETCH(&r[1], 0, TGSI_CHAN_Y); |
FETCH(&r[2], 0, TGSI_CHAN_Z); |
FETCH(&r[3], 0, TGSI_CHAN_W); |
fetch_assign_deriv_channel(mach, inst, 1, TGSI_CHAN_X, derivs[0]); |
fetch_assign_deriv_channel(mach, inst, 1, TGSI_CHAN_Y, derivs[1]); |
fetch_assign_deriv_channel(mach, inst, 1, TGSI_CHAN_Z, derivs[2]); |
fetch_texel(mach->Sampler, unit, unit, |
&r[0], &r[1], &r[2], &r[3], &ZeroVec, /* inputs */ |
derivs, offsets, tgsi_sampler_derivs_explicit, |
&r[0], &r[1], &r[2], &r[3]); /* outputs */ |
break; |
default: |
assert(0); |
} |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &r[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); |
} |
} |
} |
static void |
exec_txf(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
const uint unit = inst->Src[1].Register.Index; |
union tgsi_exec_channel r[4]; |
uint chan; |
float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]; |
int j; |
int8_t offsets[3]; |
unsigned target; |
/* always fetch all 3 offsets, overkill but keeps code simple */ |
fetch_texel_offsets(mach, inst, offsets); |
IFETCH(&r[3], 0, TGSI_CHAN_W); |
if (inst->Instruction.Opcode == TGSI_OPCODE_SAMPLE_I) { |
target = mach->SamplerViews[unit].Resource; |
} |
else { |
target = inst->Texture.Texture; |
} |
switch(target) { |
case TGSI_TEXTURE_3D: |
case TGSI_TEXTURE_2D_ARRAY: |
case TGSI_TEXTURE_SHADOW2D_ARRAY: |
IFETCH(&r[2], 0, TGSI_CHAN_Z); |
/* fallthrough */ |
case TGSI_TEXTURE_2D: |
case TGSI_TEXTURE_RECT: |
case TGSI_TEXTURE_SHADOW1D_ARRAY: |
case TGSI_TEXTURE_SHADOW2D: |
case TGSI_TEXTURE_SHADOWRECT: |
case TGSI_TEXTURE_1D_ARRAY: |
IFETCH(&r[1], 0, TGSI_CHAN_Y); |
/* fallthrough */ |
case TGSI_TEXTURE_BUFFER: |
case TGSI_TEXTURE_1D: |
case TGSI_TEXTURE_SHADOW1D: |
IFETCH(&r[0], 0, TGSI_CHAN_X); |
break; |
default: |
assert(0); |
break; |
} |
mach->Sampler->get_texel(mach->Sampler, unit, r[0].i, r[1].i, r[2].i, r[3].i, |
offsets, rgba); |
for (j = 0; j < TGSI_QUAD_SIZE; j++) { |
r[0].f[j] = rgba[0][j]; |
r[1].f[j] = rgba[1][j]; |
r[2].f[j] = rgba[2][j]; |
r[3].f[j] = rgba[3][j]; |
} |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &r[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); |
} |
} |
} |
static void |
exec_txq(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
const uint unit = inst->Src[1].Register.Index; |
int result[4]; |
union tgsi_exec_channel r[4], src; |
uint chan; |
int i,j; |
fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_INT); |
mach->Sampler->get_dims(mach->Sampler, unit, src.i[0], result); |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
for (j = 0; j < 4; j++) { |
r[j].i[i] = result[j]; |
} |
} |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &r[chan], &inst->Dst[0], inst, chan, |
TGSI_EXEC_DATA_INT); |
} |
} |
} |
static void |
exec_sample(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst, |
uint modifier, boolean compare) |
{ |
const uint resource_unit = inst->Src[1].Register.Index; |
const uint sampler_unit = inst->Src[2].Register.Index; |
union tgsi_exec_channel r[4], c1; |
const union tgsi_exec_channel *lod = &ZeroVec; |
enum tgsi_sampler_control control = tgsi_sampler_lod_none; |
uint chan; |
int8_t offsets[3]; |
/* always fetch all 3 offsets, overkill but keeps code simple */ |
fetch_texel_offsets(mach, inst, offsets); |
assert(modifier != TEX_MODIFIER_PROJECTED); |
if (modifier != TEX_MODIFIER_NONE) { |
if (modifier == TEX_MODIFIER_LOD_BIAS) { |
FETCH(&c1, 3, TGSI_CHAN_X); |
lod = &c1; |
control = tgsi_sampler_lod_bias; |
} |
else if (modifier == TEX_MODIFIER_EXPLICIT_LOD) { |
FETCH(&c1, 3, TGSI_CHAN_X); |
lod = &c1; |
control = tgsi_sampler_lod_explicit; |
} |
else { |
assert(modifier == TEX_MODIFIER_LEVEL_ZERO); |
control = tgsi_sampler_lod_zero; |
} |
} |
FETCH(&r[0], 0, TGSI_CHAN_X); |
switch (mach->SamplerViews[resource_unit].Resource) { |
case TGSI_TEXTURE_1D: |
if (compare) { |
FETCH(&r[2], 3, TGSI_CHAN_X); |
fetch_texel(mach->Sampler, resource_unit, sampler_unit, |
&r[0], &ZeroVec, &r[2], &ZeroVec, lod, /* S, T, P, C, LOD */ |
NULL, offsets, control, |
&r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ |
} |
else { |
fetch_texel(mach->Sampler, resource_unit, sampler_unit, |
&r[0], &ZeroVec, &ZeroVec, &ZeroVec, lod, /* S, T, P, C, LOD */ |
NULL, offsets, control, |
&r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ |
} |
break; |
case TGSI_TEXTURE_1D_ARRAY: |
case TGSI_TEXTURE_2D: |
case TGSI_TEXTURE_RECT: |
FETCH(&r[1], 0, TGSI_CHAN_Y); |
if (compare) { |
FETCH(&r[2], 3, TGSI_CHAN_X); |
fetch_texel(mach->Sampler, resource_unit, sampler_unit, |
&r[0], &r[1], &r[2], &ZeroVec, lod, /* S, T, P, C, LOD */ |
NULL, offsets, control, |
&r[0], &r[1], &r[2], &r[3]); /* outputs */ |
} |
else { |
fetch_texel(mach->Sampler, resource_unit, sampler_unit, |
&r[0], &r[1], &ZeroVec, &ZeroVec, lod, /* S, T, P, C, LOD */ |
NULL, offsets, control, |
&r[0], &r[1], &r[2], &r[3]); /* outputs */ |
} |
break; |
case TGSI_TEXTURE_2D_ARRAY: |
case TGSI_TEXTURE_3D: |
case TGSI_TEXTURE_CUBE: |
FETCH(&r[1], 0, TGSI_CHAN_Y); |
FETCH(&r[2], 0, TGSI_CHAN_Z); |
if(compare) { |
FETCH(&r[3], 3, TGSI_CHAN_X); |
fetch_texel(mach->Sampler, resource_unit, sampler_unit, |
&r[0], &r[1], &r[2], &r[3], lod, |
NULL, offsets, control, |
&r[0], &r[1], &r[2], &r[3]); |
} |
else { |
fetch_texel(mach->Sampler, resource_unit, sampler_unit, |
&r[0], &r[1], &r[2], &ZeroVec, lod, |
NULL, offsets, control, |
&r[0], &r[1], &r[2], &r[3]); |
} |
break; |
case TGSI_TEXTURE_CUBE_ARRAY: |
FETCH(&r[1], 0, TGSI_CHAN_Y); |
FETCH(&r[2], 0, TGSI_CHAN_Z); |
FETCH(&r[3], 0, TGSI_CHAN_W); |
if(compare) { |
FETCH(&r[4], 3, TGSI_CHAN_X); |
fetch_texel(mach->Sampler, resource_unit, sampler_unit, |
&r[0], &r[1], &r[2], &r[3], &r[4], |
NULL, offsets, control, |
&r[0], &r[1], &r[2], &r[3]); |
} |
else { |
fetch_texel(mach->Sampler, resource_unit, sampler_unit, |
&r[0], &r[1], &r[2], &r[3], lod, |
NULL, offsets, control, |
&r[0], &r[1], &r[2], &r[3]); |
} |
break; |
default: |
assert(0); |
} |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &r[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); |
} |
} |
} |
static void |
exec_sample_d(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
const uint resource_unit = inst->Src[1].Register.Index; |
const uint sampler_unit = inst->Src[2].Register.Index; |
union tgsi_exec_channel r[4]; |
float derivs[3][2][TGSI_QUAD_SIZE]; |
uint chan; |
int8_t offsets[3]; |
/* always fetch all 3 offsets, overkill but keeps code simple */ |
fetch_texel_offsets(mach, inst, offsets); |
FETCH(&r[0], 0, TGSI_CHAN_X); |
switch (mach->SamplerViews[resource_unit].Resource) { |
case TGSI_TEXTURE_1D: |
case TGSI_TEXTURE_1D_ARRAY: |
/* only 1D array actually needs Y */ |
FETCH(&r[1], 0, TGSI_CHAN_Y); |
fetch_assign_deriv_channel(mach, inst, 3, TGSI_CHAN_X, derivs[0]); |
fetch_texel(mach->Sampler, resource_unit, sampler_unit, |
&r[0], &r[1], &ZeroVec, &ZeroVec, &ZeroVec, /* S, T, P, C, LOD */ |
derivs, offsets, tgsi_sampler_derivs_explicit, |
&r[0], &r[1], &r[2], &r[3]); /* R, G, B, A */ |
break; |
case TGSI_TEXTURE_2D: |
case TGSI_TEXTURE_RECT: |
case TGSI_TEXTURE_2D_ARRAY: |
/* only 2D array actually needs Z */ |
FETCH(&r[1], 0, TGSI_CHAN_Y); |
FETCH(&r[2], 0, TGSI_CHAN_Z); |
fetch_assign_deriv_channel(mach, inst, 3, TGSI_CHAN_X, derivs[0]); |
fetch_assign_deriv_channel(mach, inst, 3, TGSI_CHAN_Y, derivs[1]); |
fetch_texel(mach->Sampler, resource_unit, sampler_unit, |
&r[0], &r[1], &r[2], &ZeroVec, &ZeroVec, /* inputs */ |
derivs, offsets, tgsi_sampler_derivs_explicit, |
&r[0], &r[1], &r[2], &r[3]); /* outputs */ |
break; |
case TGSI_TEXTURE_3D: |
case TGSI_TEXTURE_CUBE: |
case TGSI_TEXTURE_CUBE_ARRAY: |
/* only cube array actually needs W */ |
FETCH(&r[1], 0, TGSI_CHAN_Y); |
FETCH(&r[2], 0, TGSI_CHAN_Z); |
FETCH(&r[3], 0, TGSI_CHAN_W); |
fetch_assign_deriv_channel(mach, inst, 3, TGSI_CHAN_X, derivs[0]); |
fetch_assign_deriv_channel(mach, inst, 3, TGSI_CHAN_Y, derivs[1]); |
fetch_assign_deriv_channel(mach, inst, 3, TGSI_CHAN_Z, derivs[2]); |
fetch_texel(mach->Sampler, resource_unit, sampler_unit, |
&r[0], &r[1], &r[2], &r[3], &ZeroVec, |
derivs, offsets, tgsi_sampler_derivs_explicit, |
&r[0], &r[1], &r[2], &r[3]); |
break; |
default: |
assert(0); |
} |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &r[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); |
} |
} |
} |
/** |
* Evaluate a constant-valued coefficient at the position of the |
* current quad. |
*/ |
static void |
eval_constant_coef( |
struct tgsi_exec_machine *mach, |
unsigned attrib, |
unsigned chan ) |
{ |
unsigned i; |
for( i = 0; i < TGSI_QUAD_SIZE; i++ ) { |
mach->Inputs[attrib].xyzw[chan].f[i] = mach->InterpCoefs[attrib].a0[chan]; |
} |
} |
/** |
* Evaluate a linear-valued coefficient at the position of the |
* current quad. |
*/ |
static void |
eval_linear_coef( |
struct tgsi_exec_machine *mach, |
unsigned attrib, |
unsigned chan ) |
{ |
const float x = mach->QuadPos.xyzw[0].f[0]; |
const float y = mach->QuadPos.xyzw[1].f[0]; |
const float dadx = mach->InterpCoefs[attrib].dadx[chan]; |
const float dady = mach->InterpCoefs[attrib].dady[chan]; |
const float a0 = mach->InterpCoefs[attrib].a0[chan] + dadx * x + dady * y; |
mach->Inputs[attrib].xyzw[chan].f[0] = a0; |
mach->Inputs[attrib].xyzw[chan].f[1] = a0 + dadx; |
mach->Inputs[attrib].xyzw[chan].f[2] = a0 + dady; |
mach->Inputs[attrib].xyzw[chan].f[3] = a0 + dadx + dady; |
} |
/** |
* Evaluate a perspective-valued coefficient at the position of the |
* current quad. |
*/ |
static void |
eval_perspective_coef( |
struct tgsi_exec_machine *mach, |
unsigned attrib, |
unsigned chan ) |
{ |
const float x = mach->QuadPos.xyzw[0].f[0]; |
const float y = mach->QuadPos.xyzw[1].f[0]; |
const float dadx = mach->InterpCoefs[attrib].dadx[chan]; |
const float dady = mach->InterpCoefs[attrib].dady[chan]; |
const float a0 = mach->InterpCoefs[attrib].a0[chan] + dadx * x + dady * y; |
const float *w = mach->QuadPos.xyzw[3].f; |
/* divide by W here */ |
mach->Inputs[attrib].xyzw[chan].f[0] = a0 / w[0]; |
mach->Inputs[attrib].xyzw[chan].f[1] = (a0 + dadx) / w[1]; |
mach->Inputs[attrib].xyzw[chan].f[2] = (a0 + dady) / w[2]; |
mach->Inputs[attrib].xyzw[chan].f[3] = (a0 + dadx + dady) / w[3]; |
} |
typedef void (* eval_coef_func)( |
struct tgsi_exec_machine *mach, |
unsigned attrib, |
unsigned chan ); |
static void |
exec_declaration(struct tgsi_exec_machine *mach, |
const struct tgsi_full_declaration *decl) |
{ |
if (decl->Declaration.File == TGSI_FILE_SAMPLER_VIEW) { |
mach->SamplerViews[decl->Range.First] = decl->SamplerView; |
return; |
} |
if (mach->Processor == TGSI_PROCESSOR_FRAGMENT) { |
if (decl->Declaration.File == TGSI_FILE_INPUT) { |
uint first, last, mask; |
first = decl->Range.First; |
last = decl->Range.Last; |
mask = decl->Declaration.UsageMask; |
/* XXX we could remove this special-case code since |
* mach->InterpCoefs[first].a0 should already have the |
* front/back-face value. But we should first update the |
* ureg code to emit the right UsageMask value (WRITEMASK_X). |
* Then, we could remove the tgsi_exec_machine::Face field. |
*/ |
/* XXX make FACE a system value */ |
if (decl->Semantic.Name == TGSI_SEMANTIC_FACE) { |
uint i; |
assert(decl->Semantic.Index == 0); |
assert(first == last); |
for (i = 0; i < TGSI_QUAD_SIZE; i++) { |
mach->Inputs[first].xyzw[0].f[i] = mach->Face; |
} |
} else { |
eval_coef_func eval; |
uint i, j; |
switch (decl->Interp.Interpolate) { |
case TGSI_INTERPOLATE_CONSTANT: |
eval = eval_constant_coef; |
break; |
case TGSI_INTERPOLATE_LINEAR: |
eval = eval_linear_coef; |
break; |
case TGSI_INTERPOLATE_PERSPECTIVE: |
eval = eval_perspective_coef; |
break; |
case TGSI_INTERPOLATE_COLOR: |
eval = mach->flatshade_color ? eval_constant_coef : eval_perspective_coef; |
break; |
default: |
assert(0); |
return; |
} |
for (j = 0; j < TGSI_NUM_CHANNELS; j++) { |
if (mask & (1 << j)) { |
for (i = first; i <= last; i++) { |
eval(mach, i, j); |
} |
} |
} |
} |
if (DEBUG_EXECUTION) { |
uint i, j; |
for (i = first; i <= last; ++i) { |
debug_printf("IN[%2u] = ", i); |
for (j = 0; j < TGSI_NUM_CHANNELS; j++) { |
if (j > 0) { |
debug_printf(" "); |
} |
debug_printf("(%6f %u, %6f %u, %6f %u, %6f %u)\n", |
mach->Inputs[i].xyzw[0].f[j], mach->Inputs[i].xyzw[0].u[j], |
mach->Inputs[i].xyzw[1].f[j], mach->Inputs[i].xyzw[1].u[j], |
mach->Inputs[i].xyzw[2].f[j], mach->Inputs[i].xyzw[2].u[j], |
mach->Inputs[i].xyzw[3].f[j], mach->Inputs[i].xyzw[3].u[j]); |
} |
} |
} |
} |
} |
if (decl->Declaration.File == TGSI_FILE_SYSTEM_VALUE) { |
mach->SysSemanticToIndex[decl->Declaration.Semantic] = decl->Range.First; |
} |
} |
typedef void (* micro_op)(union tgsi_exec_channel *dst); |
static void |
exec_vector(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst, |
micro_op op, |
enum tgsi_exec_datatype dst_datatype) |
{ |
unsigned int chan; |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
union tgsi_exec_channel dst; |
op(&dst); |
store_dest(mach, &dst, &inst->Dst[0], inst, chan, dst_datatype); |
} |
} |
} |
typedef void (* micro_unary_op)(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src); |
static void |
exec_scalar_unary(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst, |
micro_unary_op op, |
enum tgsi_exec_datatype dst_datatype, |
enum tgsi_exec_datatype src_datatype) |
{ |
unsigned int chan; |
union tgsi_exec_channel src; |
union tgsi_exec_channel dst; |
fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_X, src_datatype); |
op(&dst, &src); |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &dst, &inst->Dst[0], inst, chan, dst_datatype); |
} |
} |
} |
static void |
exec_vector_unary(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst, |
micro_unary_op op, |
enum tgsi_exec_datatype dst_datatype, |
enum tgsi_exec_datatype src_datatype) |
{ |
unsigned int chan; |
struct tgsi_exec_vector dst; |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
union tgsi_exec_channel src; |
fetch_source(mach, &src, &inst->Src[0], chan, src_datatype); |
op(&dst.xyzw[chan], &src); |
} |
} |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &dst.xyzw[chan], &inst->Dst[0], inst, chan, dst_datatype); |
} |
} |
} |
typedef void (* micro_binary_op)(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1); |
static void |
exec_scalar_binary(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst, |
micro_binary_op op, |
enum tgsi_exec_datatype dst_datatype, |
enum tgsi_exec_datatype src_datatype) |
{ |
unsigned int chan; |
union tgsi_exec_channel src[2]; |
union tgsi_exec_channel dst; |
fetch_source(mach, &src[0], &inst->Src[0], TGSI_CHAN_X, src_datatype); |
fetch_source(mach, &src[1], &inst->Src[1], TGSI_CHAN_X, src_datatype); |
op(&dst, &src[0], &src[1]); |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &dst, &inst->Dst[0], inst, chan, dst_datatype); |
} |
} |
} |
static void |
exec_vector_binary(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst, |
micro_binary_op op, |
enum tgsi_exec_datatype dst_datatype, |
enum tgsi_exec_datatype src_datatype) |
{ |
unsigned int chan; |
struct tgsi_exec_vector dst; |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
union tgsi_exec_channel src[2]; |
fetch_source(mach, &src[0], &inst->Src[0], chan, src_datatype); |
fetch_source(mach, &src[1], &inst->Src[1], chan, src_datatype); |
op(&dst.xyzw[chan], &src[0], &src[1]); |
} |
} |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &dst.xyzw[chan], &inst->Dst[0], inst, chan, dst_datatype); |
} |
} |
} |
typedef void (* micro_trinary_op)(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1, |
const union tgsi_exec_channel *src2); |
static void |
exec_vector_trinary(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst, |
micro_trinary_op op, |
enum tgsi_exec_datatype dst_datatype, |
enum tgsi_exec_datatype src_datatype) |
{ |
unsigned int chan; |
struct tgsi_exec_vector dst; |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
union tgsi_exec_channel src[3]; |
fetch_source(mach, &src[0], &inst->Src[0], chan, src_datatype); |
fetch_source(mach, &src[1], &inst->Src[1], chan, src_datatype); |
fetch_source(mach, &src[2], &inst->Src[2], chan, src_datatype); |
op(&dst.xyzw[chan], &src[0], &src[1], &src[2]); |
} |
} |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &dst.xyzw[chan], &inst->Dst[0], inst, chan, dst_datatype); |
} |
} |
} |
static void |
exec_dp3(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
unsigned int chan; |
union tgsi_exec_channel arg[3]; |
fetch_source(mach, &arg[0], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &arg[1], &inst->Src[1], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&arg[2], &arg[0], &arg[1]); |
for (chan = TGSI_CHAN_Y; chan <= TGSI_CHAN_Z; chan++) { |
fetch_source(mach, &arg[0], &inst->Src[0], chan, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &arg[1], &inst->Src[1], chan, TGSI_EXEC_DATA_FLOAT); |
micro_mad(&arg[2], &arg[0], &arg[1], &arg[2]); |
} |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &arg[2], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); |
} |
} |
} |
static void |
exec_dp4(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
unsigned int chan; |
union tgsi_exec_channel arg[3]; |
fetch_source(mach, &arg[0], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &arg[1], &inst->Src[1], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&arg[2], &arg[0], &arg[1]); |
for (chan = TGSI_CHAN_Y; chan <= TGSI_CHAN_W; chan++) { |
fetch_source(mach, &arg[0], &inst->Src[0], chan, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &arg[1], &inst->Src[1], chan, TGSI_EXEC_DATA_FLOAT); |
micro_mad(&arg[2], &arg[0], &arg[1], &arg[2]); |
} |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &arg[2], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); |
} |
} |
} |
static void |
exec_dp2a(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
unsigned int chan; |
union tgsi_exec_channel arg[3]; |
fetch_source(mach, &arg[0], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &arg[1], &inst->Src[1], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&arg[2], &arg[0], &arg[1]); |
fetch_source(mach, &arg[0], &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &arg[1], &inst->Src[1], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
micro_mad(&arg[0], &arg[0], &arg[1], &arg[2]); |
fetch_source(mach, &arg[1], &inst->Src[2], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_add(&arg[0], &arg[0], &arg[1]); |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &arg[0], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); |
} |
} |
} |
static void |
exec_dph(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
unsigned int chan; |
union tgsi_exec_channel arg[3]; |
fetch_source(mach, &arg[0], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &arg[1], &inst->Src[1], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&arg[2], &arg[0], &arg[1]); |
fetch_source(mach, &arg[0], &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &arg[1], &inst->Src[1], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
micro_mad(&arg[2], &arg[0], &arg[1], &arg[2]); |
fetch_source(mach, &arg[0], &inst->Src[0], TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &arg[1], &inst->Src[1], TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
micro_mad(&arg[0], &arg[0], &arg[1], &arg[2]); |
fetch_source(mach, &arg[1], &inst->Src[1], TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); |
micro_add(&arg[0], &arg[0], &arg[1]); |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &arg[0], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); |
} |
} |
} |
static void |
exec_dp2(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
unsigned int chan; |
union tgsi_exec_channel arg[3]; |
fetch_source(mach, &arg[0], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &arg[1], &inst->Src[1], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&arg[2], &arg[0], &arg[1]); |
fetch_source(mach, &arg[0], &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &arg[1], &inst->Src[1], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
micro_mad(&arg[2], &arg[0], &arg[1], &arg[2]); |
for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
store_dest(mach, &arg[2], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); |
} |
} |
} |
static void |
exec_nrm4(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
unsigned int chan; |
union tgsi_exec_channel arg[4]; |
union tgsi_exec_channel scale; |
fetch_source(mach, &arg[0], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&scale, &arg[0], &arg[0]); |
for (chan = TGSI_CHAN_Y; chan <= TGSI_CHAN_W; chan++) { |
union tgsi_exec_channel product; |
fetch_source(mach, &arg[chan], &inst->Src[0], chan, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&product, &arg[chan], &arg[chan]); |
micro_add(&scale, &scale, &product); |
} |
micro_rsq(&scale, &scale); |
for (chan = TGSI_CHAN_X; chan <= TGSI_CHAN_W; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
micro_mul(&arg[chan], &arg[chan], &scale); |
store_dest(mach, &arg[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); |
} |
} |
} |
static void |
exec_nrm3(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XYZ) { |
unsigned int chan; |
union tgsi_exec_channel arg[3]; |
union tgsi_exec_channel scale; |
fetch_source(mach, &arg[0], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&scale, &arg[0], &arg[0]); |
for (chan = TGSI_CHAN_Y; chan <= TGSI_CHAN_Z; chan++) { |
union tgsi_exec_channel product; |
fetch_source(mach, &arg[chan], &inst->Src[0], chan, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&product, &arg[chan], &arg[chan]); |
micro_add(&scale, &scale, &product); |
} |
micro_rsq(&scale, &scale); |
for (chan = TGSI_CHAN_X; chan <= TGSI_CHAN_Z; chan++) { |
if (inst->Dst[0].Register.WriteMask & (1 << chan)) { |
micro_mul(&arg[chan], &arg[chan], &scale); |
store_dest(mach, &arg[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT); |
} |
} |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_W) { |
store_dest(mach, &OneVec, &inst->Dst[0], inst, TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); |
} |
} |
static void |
exec_scs(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XY) { |
union tgsi_exec_channel arg; |
union tgsi_exec_channel result; |
fetch_source(mach, &arg, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_X) { |
micro_cos(&result, &arg); |
store_dest(mach, &result, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) { |
micro_sin(&result, &arg); |
store_dest(mach, &result, &inst->Dst[0], inst, TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
} |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Z) { |
store_dest(mach, &ZeroVec, &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_W) { |
store_dest(mach, &OneVec, &inst->Dst[0], inst, TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); |
} |
} |
static void |
exec_x2d(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
union tgsi_exec_channel r[4]; |
union tgsi_exec_channel d[2]; |
fetch_source(mach, &r[0], &inst->Src[1], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &r[1], &inst->Src[1], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XZ) { |
fetch_source(mach, &r[2], &inst->Src[2], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[2], &r[2], &r[0]); |
fetch_source(mach, &r[3], &inst->Src[2], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[3], &r[3], &r[1]); |
micro_add(&r[2], &r[2], &r[3]); |
fetch_source(mach, &r[3], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_add(&d[0], &r[2], &r[3]); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_YW) { |
fetch_source(mach, &r[2], &inst->Src[2], TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[2], &r[2], &r[0]); |
fetch_source(mach, &r[3], &inst->Src[2], TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[3], &r[3], &r[1]); |
micro_add(&r[2], &r[2], &r[3]); |
fetch_source(mach, &r[3], &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
micro_add(&d[1], &r[2], &r[3]); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_X) { |
store_dest(mach, &d[0], &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) { |
store_dest(mach, &d[1], &inst->Dst[0], inst, TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Z) { |
store_dest(mach, &d[0], &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_W) { |
store_dest(mach, &d[1], &inst->Dst[0], inst, TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); |
} |
} |
static void |
exec_rfl(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
union tgsi_exec_channel r[9]; |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_XYZ) { |
/* r0 = dp3(src0, src0) */ |
fetch_source(mach, &r[2], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[0], &r[2], &r[2]); |
fetch_source(mach, &r[4], &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[8], &r[4], &r[4]); |
micro_add(&r[0], &r[0], &r[8]); |
fetch_source(mach, &r[6], &inst->Src[0], TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[8], &r[6], &r[6]); |
micro_add(&r[0], &r[0], &r[8]); |
/* r1 = dp3(src0, src1) */ |
fetch_source(mach, &r[3], &inst->Src[1], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[1], &r[2], &r[3]); |
fetch_source(mach, &r[5], &inst->Src[1], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[8], &r[4], &r[5]); |
micro_add(&r[1], &r[1], &r[8]); |
fetch_source(mach, &r[7], &inst->Src[1], TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[8], &r[6], &r[7]); |
micro_add(&r[1], &r[1], &r[8]); |
/* r1 = 2 * r1 / r0 */ |
micro_add(&r[1], &r[1], &r[1]); |
micro_div(&r[1], &r[1], &r[0]); |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_X) { |
micro_mul(&r[2], &r[2], &r[1]); |
micro_sub(&r[2], &r[2], &r[3]); |
store_dest(mach, &r[2], &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) { |
micro_mul(&r[4], &r[4], &r[1]); |
micro_sub(&r[4], &r[4], &r[5]); |
store_dest(mach, &r[4], &inst->Dst[0], inst, TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Z) { |
micro_mul(&r[6], &r[6], &r[1]); |
micro_sub(&r[6], &r[6], &r[7]); |
store_dest(mach, &r[6], &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
} |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_W) { |
store_dest(mach, &OneVec, &inst->Dst[0], inst, TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); |
} |
} |
static void |
exec_xpd(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
union tgsi_exec_channel r[6]; |
union tgsi_exec_channel d[3]; |
fetch_source(mach, &r[0], &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &r[1], &inst->Src[1], TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[2], &r[0], &r[1]); |
fetch_source(mach, &r[3], &inst->Src[0], TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &r[4], &inst->Src[1], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[5], &r[3], &r[4] ); |
micro_sub(&d[TGSI_CHAN_X], &r[2], &r[5]); |
fetch_source(mach, &r[2], &inst->Src[1], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[3], &r[3], &r[2]); |
fetch_source(mach, &r[5], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&r[1], &r[1], &r[5]); |
micro_sub(&d[TGSI_CHAN_Y], &r[3], &r[1]); |
micro_mul(&r[5], &r[5], &r[4]); |
micro_mul(&r[0], &r[0], &r[2]); |
micro_sub(&d[TGSI_CHAN_Z], &r[5], &r[0]); |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_X) { |
store_dest(mach, &d[TGSI_CHAN_X], &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) { |
store_dest(mach, &d[TGSI_CHAN_Y], &inst->Dst[0], inst, TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Z) { |
store_dest(mach, &d[TGSI_CHAN_Z], &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_W) { |
store_dest(mach, &OneVec, &inst->Dst[0], inst, TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); |
} |
} |
static void |
exec_dst(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
union tgsi_exec_channel r[2]; |
union tgsi_exec_channel d[4]; |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) { |
fetch_source(mach, &r[0], &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
fetch_source(mach, &r[1], &inst->Src[1], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
micro_mul(&d[TGSI_CHAN_Y], &r[0], &r[1]); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Z) { |
fetch_source(mach, &d[TGSI_CHAN_Z], &inst->Src[0], TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_W) { |
fetch_source(mach, &d[TGSI_CHAN_W], &inst->Src[1], TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_X) { |
store_dest(mach, &OneVec, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) { |
store_dest(mach, &d[TGSI_CHAN_Y], &inst->Dst[0], inst, TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Z) { |
store_dest(mach, &d[TGSI_CHAN_Z], &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_W) { |
store_dest(mach, &d[TGSI_CHAN_W], &inst->Dst[0], inst, TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); |
} |
} |
static void |
exec_log(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
union tgsi_exec_channel r[3]; |
fetch_source(mach, &r[0], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_abs(&r[2], &r[0]); /* r2 = abs(r0) */ |
micro_lg2(&r[1], &r[2]); /* r1 = lg2(r2) */ |
micro_flr(&r[0], &r[1]); /* r0 = floor(r1) */ |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_X) { |
store_dest(mach, &r[0], &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) { |
micro_exp2(&r[0], &r[0]); /* r0 = 2 ^ r0 */ |
micro_div(&r[0], &r[2], &r[0]); /* r0 = r2 / r0 */ |
store_dest(mach, &r[0], &inst->Dst[0], inst, TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Z) { |
store_dest(mach, &r[1], &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_W) { |
store_dest(mach, &OneVec, &inst->Dst[0], inst, TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); |
} |
} |
static void |
exec_exp(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
union tgsi_exec_channel r[3]; |
fetch_source(mach, &r[0], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
micro_flr(&r[1], &r[0]); /* r1 = floor(r0) */ |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_X) { |
micro_exp2(&r[2], &r[1]); /* r2 = 2 ^ r1 */ |
store_dest(mach, &r[2], &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) { |
micro_sub(&r[2], &r[0], &r[1]); /* r2 = r0 - r1 */ |
store_dest(mach, &r[2], &inst->Dst[0], inst, TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Z) { |
micro_exp2(&r[2], &r[0]); /* r2 = 2 ^ r0 */ |
store_dest(mach, &r[2], &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_W) { |
store_dest(mach, &OneVec, &inst->Dst[0], inst, TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); |
} |
} |
static void |
exec_lit(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
union tgsi_exec_channel r[3]; |
union tgsi_exec_channel d[3]; |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_YZ) { |
fetch_source(mach, &r[0], &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Z) { |
fetch_source(mach, &r[1], &inst->Src[0], TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
micro_max(&r[1], &r[1], &ZeroVec); |
fetch_source(mach, &r[2], &inst->Src[0], TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); |
micro_min(&r[2], &r[2], &P128Vec); |
micro_max(&r[2], &r[2], &M128Vec); |
micro_pow(&r[1], &r[1], &r[2]); |
micro_lt(&d[TGSI_CHAN_Z], &ZeroVec, &r[0], &r[1], &ZeroVec); |
store_dest(mach, &d[TGSI_CHAN_Z], &inst->Dst[0], inst, TGSI_CHAN_Z, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_Y) { |
micro_max(&d[TGSI_CHAN_Y], &r[0], &ZeroVec); |
store_dest(mach, &d[TGSI_CHAN_Y], &inst->Dst[0], inst, TGSI_CHAN_Y, TGSI_EXEC_DATA_FLOAT); |
} |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_X) { |
store_dest(mach, &OneVec, &inst->Dst[0], inst, TGSI_CHAN_X, TGSI_EXEC_DATA_FLOAT); |
} |
if (inst->Dst[0].Register.WriteMask & TGSI_WRITEMASK_W) { |
store_dest(mach, &OneVec, &inst->Dst[0], inst, TGSI_CHAN_W, TGSI_EXEC_DATA_FLOAT); |
} |
} |
static void |
exec_break(struct tgsi_exec_machine *mach) |
{ |
if (mach->BreakType == TGSI_EXEC_BREAK_INSIDE_LOOP) { |
/* turn off loop channels for each enabled exec channel */ |
mach->LoopMask &= ~mach->ExecMask; |
/* Todo: if mach->LoopMask == 0, jump to end of loop */ |
UPDATE_EXEC_MASK(mach); |
} else { |
assert(mach->BreakType == TGSI_EXEC_BREAK_INSIDE_SWITCH); |
mach->Switch.mask = 0x0; |
UPDATE_EXEC_MASK(mach); |
} |
} |
static void |
exec_switch(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
assert(mach->SwitchStackTop < TGSI_EXEC_MAX_SWITCH_NESTING); |
assert(mach->BreakStackTop < TGSI_EXEC_MAX_BREAK_STACK); |
mach->SwitchStack[mach->SwitchStackTop++] = mach->Switch; |
fetch_source(mach, &mach->Switch.selector, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_UINT); |
mach->Switch.mask = 0x0; |
mach->Switch.defaultMask = 0x0; |
mach->BreakStack[mach->BreakStackTop++] = mach->BreakType; |
mach->BreakType = TGSI_EXEC_BREAK_INSIDE_SWITCH; |
UPDATE_EXEC_MASK(mach); |
} |
static void |
exec_case(struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst) |
{ |
uint prevMask = mach->SwitchStack[mach->SwitchStackTop - 1].mask; |
union tgsi_exec_channel src; |
uint mask = 0; |
fetch_source(mach, &src, &inst->Src[0], TGSI_CHAN_X, TGSI_EXEC_DATA_UINT); |
if (mach->Switch.selector.u[0] == src.u[0]) { |
mask |= 0x1; |
} |
if (mach->Switch.selector.u[1] == src.u[1]) { |
mask |= 0x2; |
} |
if (mach->Switch.selector.u[2] == src.u[2]) { |
mask |= 0x4; |
} |
if (mach->Switch.selector.u[3] == src.u[3]) { |
mask |= 0x8; |
} |
mach->Switch.defaultMask |= mask; |
mach->Switch.mask |= mask & prevMask; |
UPDATE_EXEC_MASK(mach); |
} |
/* FIXME: this will only work if default is last */ |
static void |
exec_default(struct tgsi_exec_machine *mach) |
{ |
uint prevMask = mach->SwitchStack[mach->SwitchStackTop - 1].mask; |
mach->Switch.mask |= ~mach->Switch.defaultMask & prevMask; |
UPDATE_EXEC_MASK(mach); |
} |
static void |
exec_endswitch(struct tgsi_exec_machine *mach) |
{ |
mach->Switch = mach->SwitchStack[--mach->SwitchStackTop]; |
mach->BreakType = mach->BreakStack[--mach->BreakStackTop]; |
UPDATE_EXEC_MASK(mach); |
} |
static void |
micro_i2f(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = (float)src->i[0]; |
dst->f[1] = (float)src->i[1]; |
dst->f[2] = (float)src->i[2]; |
dst->f[3] = (float)src->i[3]; |
} |
static void |
micro_not(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->u[0] = ~src->u[0]; |
dst->u[1] = ~src->u[1]; |
dst->u[2] = ~src->u[2]; |
dst->u[3] = ~src->u[3]; |
} |
static void |
micro_shl(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src0->u[0] << src1->u[0]; |
dst->u[1] = src0->u[1] << src1->u[1]; |
dst->u[2] = src0->u[2] << src1->u[2]; |
dst->u[3] = src0->u[3] << src1->u[3]; |
} |
static void |
micro_and(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src0->u[0] & src1->u[0]; |
dst->u[1] = src0->u[1] & src1->u[1]; |
dst->u[2] = src0->u[2] & src1->u[2]; |
dst->u[3] = src0->u[3] & src1->u[3]; |
} |
static void |
micro_or(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src0->u[0] | src1->u[0]; |
dst->u[1] = src0->u[1] | src1->u[1]; |
dst->u[2] = src0->u[2] | src1->u[2]; |
dst->u[3] = src0->u[3] | src1->u[3]; |
} |
static void |
micro_xor(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src0->u[0] ^ src1->u[0]; |
dst->u[1] = src0->u[1] ^ src1->u[1]; |
dst->u[2] = src0->u[2] ^ src1->u[2]; |
dst->u[3] = src0->u[3] ^ src1->u[3]; |
} |
static void |
micro_mod(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->i[0] = src0->i[0] % src1->i[0]; |
dst->i[1] = src0->i[1] % src1->i[1]; |
dst->i[2] = src0->i[2] % src1->i[2]; |
dst->i[3] = src0->i[3] % src1->i[3]; |
} |
static void |
micro_f2i(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->i[0] = (int)src->f[0]; |
dst->i[1] = (int)src->f[1]; |
dst->i[2] = (int)src->f[2]; |
dst->i[3] = (int)src->f[3]; |
} |
static void |
micro_idiv(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->i[0] = src0->i[0] / src1->i[0]; |
dst->i[1] = src0->i[1] / src1->i[1]; |
dst->i[2] = src0->i[2] / src1->i[2]; |
dst->i[3] = src0->i[3] / src1->i[3]; |
} |
static void |
micro_imax(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->i[0] = src0->i[0] > src1->i[0] ? src0->i[0] : src1->i[0]; |
dst->i[1] = src0->i[1] > src1->i[1] ? src0->i[1] : src1->i[1]; |
dst->i[2] = src0->i[2] > src1->i[2] ? src0->i[2] : src1->i[2]; |
dst->i[3] = src0->i[3] > src1->i[3] ? src0->i[3] : src1->i[3]; |
} |
static void |
micro_imin(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->i[0] = src0->i[0] < src1->i[0] ? src0->i[0] : src1->i[0]; |
dst->i[1] = src0->i[1] < src1->i[1] ? src0->i[1] : src1->i[1]; |
dst->i[2] = src0->i[2] < src1->i[2] ? src0->i[2] : src1->i[2]; |
dst->i[3] = src0->i[3] < src1->i[3] ? src0->i[3] : src1->i[3]; |
} |
static void |
micro_isge(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->i[0] = src0->i[0] >= src1->i[0] ? -1 : 0; |
dst->i[1] = src0->i[1] >= src1->i[1] ? -1 : 0; |
dst->i[2] = src0->i[2] >= src1->i[2] ? -1 : 0; |
dst->i[3] = src0->i[3] >= src1->i[3] ? -1 : 0; |
} |
static void |
micro_ishr(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->i[0] = src0->i[0] >> src1->i[0]; |
dst->i[1] = src0->i[1] >> src1->i[1]; |
dst->i[2] = src0->i[2] >> src1->i[2]; |
dst->i[3] = src0->i[3] >> src1->i[3]; |
} |
static void |
micro_islt(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->i[0] = src0->i[0] < src1->i[0] ? -1 : 0; |
dst->i[1] = src0->i[1] < src1->i[1] ? -1 : 0; |
dst->i[2] = src0->i[2] < src1->i[2] ? -1 : 0; |
dst->i[3] = src0->i[3] < src1->i[3] ? -1 : 0; |
} |
static void |
micro_f2u(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->u[0] = (uint)src->f[0]; |
dst->u[1] = (uint)src->f[1]; |
dst->u[2] = (uint)src->f[2]; |
dst->u[3] = (uint)src->f[3]; |
} |
static void |
micro_u2f(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->f[0] = (float)src->u[0]; |
dst->f[1] = (float)src->u[1]; |
dst->f[2] = (float)src->u[2]; |
dst->f[3] = (float)src->u[3]; |
} |
static void |
micro_uadd(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src0->u[0] + src1->u[0]; |
dst->u[1] = src0->u[1] + src1->u[1]; |
dst->u[2] = src0->u[2] + src1->u[2]; |
dst->u[3] = src0->u[3] + src1->u[3]; |
} |
static void |
micro_udiv(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src1->u[0] ? src0->u[0] / src1->u[0] : ~0u; |
dst->u[1] = src1->u[1] ? src0->u[1] / src1->u[1] : ~0u; |
dst->u[2] = src1->u[2] ? src0->u[2] / src1->u[2] : ~0u; |
dst->u[3] = src1->u[3] ? src0->u[3] / src1->u[3] : ~0u; |
} |
static void |
micro_umad(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1, |
const union tgsi_exec_channel *src2) |
{ |
dst->u[0] = src0->u[0] * src1->u[0] + src2->u[0]; |
dst->u[1] = src0->u[1] * src1->u[1] + src2->u[1]; |
dst->u[2] = src0->u[2] * src1->u[2] + src2->u[2]; |
dst->u[3] = src0->u[3] * src1->u[3] + src2->u[3]; |
} |
static void |
micro_umax(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src0->u[0] > src1->u[0] ? src0->u[0] : src1->u[0]; |
dst->u[1] = src0->u[1] > src1->u[1] ? src0->u[1] : src1->u[1]; |
dst->u[2] = src0->u[2] > src1->u[2] ? src0->u[2] : src1->u[2]; |
dst->u[3] = src0->u[3] > src1->u[3] ? src0->u[3] : src1->u[3]; |
} |
static void |
micro_umin(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src0->u[0] < src1->u[0] ? src0->u[0] : src1->u[0]; |
dst->u[1] = src0->u[1] < src1->u[1] ? src0->u[1] : src1->u[1]; |
dst->u[2] = src0->u[2] < src1->u[2] ? src0->u[2] : src1->u[2]; |
dst->u[3] = src0->u[3] < src1->u[3] ? src0->u[3] : src1->u[3]; |
} |
static void |
micro_umod(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src1->u[0] ? src0->u[0] % src1->u[0] : ~0u; |
dst->u[1] = src1->u[1] ? src0->u[1] % src1->u[1] : ~0u; |
dst->u[2] = src1->u[2] ? src0->u[2] % src1->u[2] : ~0u; |
dst->u[3] = src1->u[3] ? src0->u[3] % src1->u[3] : ~0u; |
} |
static void |
micro_umul(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src0->u[0] * src1->u[0]; |
dst->u[1] = src0->u[1] * src1->u[1]; |
dst->u[2] = src0->u[2] * src1->u[2]; |
dst->u[3] = src0->u[3] * src1->u[3]; |
} |
static void |
micro_useq(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src0->u[0] == src1->u[0] ? ~0 : 0; |
dst->u[1] = src0->u[1] == src1->u[1] ? ~0 : 0; |
dst->u[2] = src0->u[2] == src1->u[2] ? ~0 : 0; |
dst->u[3] = src0->u[3] == src1->u[3] ? ~0 : 0; |
} |
static void |
micro_usge(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src0->u[0] >= src1->u[0] ? ~0 : 0; |
dst->u[1] = src0->u[1] >= src1->u[1] ? ~0 : 0; |
dst->u[2] = src0->u[2] >= src1->u[2] ? ~0 : 0; |
dst->u[3] = src0->u[3] >= src1->u[3] ? ~0 : 0; |
} |
static void |
micro_ushr(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src0->u[0] >> src1->u[0]; |
dst->u[1] = src0->u[1] >> src1->u[1]; |
dst->u[2] = src0->u[2] >> src1->u[2]; |
dst->u[3] = src0->u[3] >> src1->u[3]; |
} |
static void |
micro_uslt(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src0->u[0] < src1->u[0] ? ~0 : 0; |
dst->u[1] = src0->u[1] < src1->u[1] ? ~0 : 0; |
dst->u[2] = src0->u[2] < src1->u[2] ? ~0 : 0; |
dst->u[3] = src0->u[3] < src1->u[3] ? ~0 : 0; |
} |
static void |
micro_usne(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1) |
{ |
dst->u[0] = src0->u[0] != src1->u[0] ? ~0 : 0; |
dst->u[1] = src0->u[1] != src1->u[1] ? ~0 : 0; |
dst->u[2] = src0->u[2] != src1->u[2] ? ~0 : 0; |
dst->u[3] = src0->u[3] != src1->u[3] ? ~0 : 0; |
} |
static void |
micro_uarl(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src) |
{ |
dst->i[0] = src->u[0]; |
dst->i[1] = src->u[1]; |
dst->i[2] = src->u[2]; |
dst->i[3] = src->u[3]; |
} |
static void |
micro_ucmp(union tgsi_exec_channel *dst, |
const union tgsi_exec_channel *src0, |
const union tgsi_exec_channel *src1, |
const union tgsi_exec_channel *src2) |
{ |
dst->u[0] = src0->u[0] ? src1->u[0] : src2->u[0]; |
dst->u[1] = src0->u[1] ? src1->u[1] : src2->u[1]; |
dst->u[2] = src0->u[2] ? src1->u[2] : src2->u[2]; |
dst->u[3] = src0->u[3] ? src1->u[3] : src2->u[3]; |
} |
static void |
exec_instruction( |
struct tgsi_exec_machine *mach, |
const struct tgsi_full_instruction *inst, |
int *pc ) |
{ |
union tgsi_exec_channel r[10]; |
(*pc)++; |
switch (inst->Instruction.Opcode) { |
case TGSI_OPCODE_ARL: |
exec_vector_unary(mach, inst, micro_arl, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_MOV: |
exec_vector_unary(mach, inst, micro_mov, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_LIT: |
exec_lit(mach, inst); |
break; |
case TGSI_OPCODE_RCP: |
exec_scalar_unary(mach, inst, micro_rcp, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_RSQ: |
exec_scalar_unary(mach, inst, micro_rsq, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_EXP: |
exec_exp(mach, inst); |
break; |
case TGSI_OPCODE_LOG: |
exec_log(mach, inst); |
break; |
case TGSI_OPCODE_MUL: |
exec_vector_binary(mach, inst, micro_mul, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_ADD: |
exec_vector_binary(mach, inst, micro_add, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_DP3: |
exec_dp3(mach, inst); |
break; |
case TGSI_OPCODE_DP4: |
exec_dp4(mach, inst); |
break; |
case TGSI_OPCODE_DST: |
exec_dst(mach, inst); |
break; |
case TGSI_OPCODE_MIN: |
exec_vector_binary(mach, inst, micro_min, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_MAX: |
exec_vector_binary(mach, inst, micro_max, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_SLT: |
exec_vector_binary(mach, inst, micro_slt, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_SGE: |
exec_vector_binary(mach, inst, micro_sge, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_MAD: |
exec_vector_trinary(mach, inst, micro_mad, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_SUB: |
exec_vector_binary(mach, inst, micro_sub, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_LRP: |
exec_vector_trinary(mach, inst, micro_lrp, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_CND: |
exec_vector_trinary(mach, inst, micro_cnd, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_SQRT: |
exec_scalar_unary(mach, inst, micro_sqrt, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_DP2A: |
exec_dp2a(mach, inst); |
break; |
case TGSI_OPCODE_FRC: |
exec_vector_unary(mach, inst, micro_frc, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_CLAMP: |
exec_vector_trinary(mach, inst, micro_clamp, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_FLR: |
exec_vector_unary(mach, inst, micro_flr, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_ROUND: |
exec_vector_unary(mach, inst, micro_rnd, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_EX2: |
exec_scalar_unary(mach, inst, micro_exp2, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_LG2: |
exec_scalar_unary(mach, inst, micro_lg2, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_POW: |
exec_scalar_binary(mach, inst, micro_pow, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_XPD: |
exec_xpd(mach, inst); |
break; |
case TGSI_OPCODE_ABS: |
exec_vector_unary(mach, inst, micro_abs, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_RCC: |
exec_scalar_unary(mach, inst, micro_rcc, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_DPH: |
exec_dph(mach, inst); |
break; |
case TGSI_OPCODE_COS: |
exec_scalar_unary(mach, inst, micro_cos, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_DDX: |
exec_vector_unary(mach, inst, micro_ddx, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_DDY: |
exec_vector_unary(mach, inst, micro_ddy, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_KILL: |
exec_kill (mach, inst); |
break; |
case TGSI_OPCODE_KILL_IF: |
exec_kill_if (mach, inst); |
break; |
case TGSI_OPCODE_PK2H: |
assert (0); |
break; |
case TGSI_OPCODE_PK2US: |
assert (0); |
break; |
case TGSI_OPCODE_PK4B: |
assert (0); |
break; |
case TGSI_OPCODE_PK4UB: |
assert (0); |
break; |
case TGSI_OPCODE_RFL: |
exec_rfl(mach, inst); |
break; |
case TGSI_OPCODE_SEQ: |
exec_vector_binary(mach, inst, micro_seq, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_SFL: |
exec_vector(mach, inst, micro_sfl, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_SGT: |
exec_vector_binary(mach, inst, micro_sgt, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_SIN: |
exec_scalar_unary(mach, inst, micro_sin, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_SLE: |
exec_vector_binary(mach, inst, micro_sle, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_SNE: |
exec_vector_binary(mach, inst, micro_sne, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_STR: |
exec_vector(mach, inst, micro_str, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_TEX: |
/* simple texture lookup */ |
/* src[0] = texcoord */ |
/* src[1] = sampler unit */ |
exec_tex(mach, inst, TEX_MODIFIER_NONE, 1); |
break; |
case TGSI_OPCODE_TXB: |
/* Texture lookup with lod bias */ |
/* src[0] = texcoord (src[0].w = LOD bias) */ |
/* src[1] = sampler unit */ |
exec_tex(mach, inst, TEX_MODIFIER_LOD_BIAS, 1); |
break; |
case TGSI_OPCODE_TXD: |
/* Texture lookup with explict partial derivatives */ |
/* src[0] = texcoord */ |
/* src[1] = d[strq]/dx */ |
/* src[2] = d[strq]/dy */ |
/* src[3] = sampler unit */ |
exec_txd(mach, inst); |
break; |
case TGSI_OPCODE_TXL: |
/* Texture lookup with explit LOD */ |
/* src[0] = texcoord (src[0].w = LOD) */ |
/* src[1] = sampler unit */ |
exec_tex(mach, inst, TEX_MODIFIER_EXPLICIT_LOD, 1); |
break; |
case TGSI_OPCODE_TXP: |
/* Texture lookup with projection */ |
/* src[0] = texcoord (src[0].w = projection) */ |
/* src[1] = sampler unit */ |
exec_tex(mach, inst, TEX_MODIFIER_PROJECTED, 1); |
break; |
case TGSI_OPCODE_UP2H: |
assert (0); |
break; |
case TGSI_OPCODE_UP2US: |
assert (0); |
break; |
case TGSI_OPCODE_UP4B: |
assert (0); |
break; |
case TGSI_OPCODE_UP4UB: |
assert (0); |
break; |
case TGSI_OPCODE_X2D: |
exec_x2d(mach, inst); |
break; |
case TGSI_OPCODE_ARA: |
assert (0); |
break; |
case TGSI_OPCODE_ARR: |
exec_vector_unary(mach, inst, micro_arr, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_BRA: |
assert (0); |
break; |
case TGSI_OPCODE_CAL: |
/* skip the call if no execution channels are enabled */ |
if (mach->ExecMask) { |
/* do the call */ |
/* First, record the depths of the execution stacks. |
* This is important for deeply nested/looped return statements. |
* We have to unwind the stacks by the correct amount. For a |
* real code generator, we could determine the number of entries |
* to pop off each stack with simple static analysis and avoid |
* implementing this data structure at run time. |
*/ |
mach->CallStack[mach->CallStackTop].CondStackTop = mach->CondStackTop; |
mach->CallStack[mach->CallStackTop].LoopStackTop = mach->LoopStackTop; |
mach->CallStack[mach->CallStackTop].ContStackTop = mach->ContStackTop; |
mach->CallStack[mach->CallStackTop].SwitchStackTop = mach->SwitchStackTop; |
mach->CallStack[mach->CallStackTop].BreakStackTop = mach->BreakStackTop; |
/* note that PC was already incremented above */ |
mach->CallStack[mach->CallStackTop].ReturnAddr = *pc; |
mach->CallStackTop++; |
/* Second, push the Cond, Loop, Cont, Func stacks */ |
assert(mach->CondStackTop < TGSI_EXEC_MAX_COND_NESTING); |
assert(mach->LoopStackTop < TGSI_EXEC_MAX_LOOP_NESTING); |
assert(mach->ContStackTop < TGSI_EXEC_MAX_LOOP_NESTING); |
assert(mach->SwitchStackTop < TGSI_EXEC_MAX_SWITCH_NESTING); |
assert(mach->BreakStackTop < TGSI_EXEC_MAX_BREAK_STACK); |
assert(mach->FuncStackTop < TGSI_EXEC_MAX_CALL_NESTING); |
mach->CondStack[mach->CondStackTop++] = mach->CondMask; |
mach->LoopStack[mach->LoopStackTop++] = mach->LoopMask; |
mach->ContStack[mach->ContStackTop++] = mach->ContMask; |
mach->SwitchStack[mach->SwitchStackTop++] = mach->Switch; |
mach->BreakStack[mach->BreakStackTop++] = mach->BreakType; |
mach->FuncStack[mach->FuncStackTop++] = mach->FuncMask; |
/* Finally, jump to the subroutine */ |
*pc = inst->Label.Label; |
} |
break; |
case TGSI_OPCODE_RET: |
mach->FuncMask &= ~mach->ExecMask; |
UPDATE_EXEC_MASK(mach); |
if (mach->FuncMask == 0x0) { |
/* really return now (otherwise, keep executing */ |
if (mach->CallStackTop == 0) { |
/* returning from main() */ |
mach->CondStackTop = 0; |
mach->LoopStackTop = 0; |
*pc = -1; |
return; |
} |
assert(mach->CallStackTop > 0); |
mach->CallStackTop--; |
mach->CondStackTop = mach->CallStack[mach->CallStackTop].CondStackTop; |
mach->CondMask = mach->CondStack[mach->CondStackTop]; |
mach->LoopStackTop = mach->CallStack[mach->CallStackTop].LoopStackTop; |
mach->LoopMask = mach->LoopStack[mach->LoopStackTop]; |
mach->ContStackTop = mach->CallStack[mach->CallStackTop].ContStackTop; |
mach->ContMask = mach->ContStack[mach->ContStackTop]; |
mach->SwitchStackTop = mach->CallStack[mach->CallStackTop].SwitchStackTop; |
mach->Switch = mach->SwitchStack[mach->SwitchStackTop]; |
mach->BreakStackTop = mach->CallStack[mach->CallStackTop].BreakStackTop; |
mach->BreakType = mach->BreakStack[mach->BreakStackTop]; |
assert(mach->FuncStackTop > 0); |
mach->FuncMask = mach->FuncStack[--mach->FuncStackTop]; |
*pc = mach->CallStack[mach->CallStackTop].ReturnAddr; |
UPDATE_EXEC_MASK(mach); |
} |
break; |
case TGSI_OPCODE_SSG: |
exec_vector_unary(mach, inst, micro_sgn, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_CMP: |
exec_vector_trinary(mach, inst, micro_cmp, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_SCS: |
exec_scs(mach, inst); |
break; |
case TGSI_OPCODE_NRM: |
exec_nrm3(mach, inst); |
break; |
case TGSI_OPCODE_NRM4: |
exec_nrm4(mach, inst); |
break; |
case TGSI_OPCODE_DIV: |
exec_vector_binary(mach, inst, micro_div, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_DP2: |
exec_dp2(mach, inst); |
break; |
case TGSI_OPCODE_IF: |
/* push CondMask */ |
assert(mach->CondStackTop < TGSI_EXEC_MAX_COND_NESTING); |
mach->CondStack[mach->CondStackTop++] = mach->CondMask; |
FETCH( &r[0], 0, TGSI_CHAN_X ); |
/* update CondMask */ |
if( ! r[0].f[0] ) { |
mach->CondMask &= ~0x1; |
} |
if( ! r[0].f[1] ) { |
mach->CondMask &= ~0x2; |
} |
if( ! r[0].f[2] ) { |
mach->CondMask &= ~0x4; |
} |
if( ! r[0].f[3] ) { |
mach->CondMask &= ~0x8; |
} |
UPDATE_EXEC_MASK(mach); |
/* Todo: If CondMask==0, jump to ELSE */ |
break; |
case TGSI_OPCODE_UIF: |
/* push CondMask */ |
assert(mach->CondStackTop < TGSI_EXEC_MAX_COND_NESTING); |
mach->CondStack[mach->CondStackTop++] = mach->CondMask; |
IFETCH( &r[0], 0, TGSI_CHAN_X ); |
/* update CondMask */ |
if( ! r[0].u[0] ) { |
mach->CondMask &= ~0x1; |
} |
if( ! r[0].u[1] ) { |
mach->CondMask &= ~0x2; |
} |
if( ! r[0].u[2] ) { |
mach->CondMask &= ~0x4; |
} |
if( ! r[0].u[3] ) { |
mach->CondMask &= ~0x8; |
} |
UPDATE_EXEC_MASK(mach); |
/* Todo: If CondMask==0, jump to ELSE */ |
break; |
case TGSI_OPCODE_ELSE: |
/* invert CondMask wrt previous mask */ |
{ |
uint prevMask; |
assert(mach->CondStackTop > 0); |
prevMask = mach->CondStack[mach->CondStackTop - 1]; |
mach->CondMask = ~mach->CondMask & prevMask; |
UPDATE_EXEC_MASK(mach); |
/* Todo: If CondMask==0, jump to ENDIF */ |
} |
break; |
case TGSI_OPCODE_ENDIF: |
/* pop CondMask */ |
assert(mach->CondStackTop > 0); |
mach->CondMask = mach->CondStack[--mach->CondStackTop]; |
UPDATE_EXEC_MASK(mach); |
break; |
case TGSI_OPCODE_END: |
/* make sure we end primitives which haven't |
* been explicitly emitted */ |
conditional_emit_primitive(mach); |
/* halt execution */ |
*pc = -1; |
break; |
case TGSI_OPCODE_PUSHA: |
assert (0); |
break; |
case TGSI_OPCODE_POPA: |
assert (0); |
break; |
case TGSI_OPCODE_CEIL: |
exec_vector_unary(mach, inst, micro_ceil, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_I2F: |
exec_vector_unary(mach, inst, micro_i2f, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_INT); |
break; |
case TGSI_OPCODE_NOT: |
exec_vector_unary(mach, inst, micro_not, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_TRUNC: |
exec_vector_unary(mach, inst, micro_trunc, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_SHL: |
exec_vector_binary(mach, inst, micro_shl, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_AND: |
exec_vector_binary(mach, inst, micro_and, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_OR: |
exec_vector_binary(mach, inst, micro_or, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_MOD: |
exec_vector_binary(mach, inst, micro_mod, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); |
break; |
case TGSI_OPCODE_XOR: |
exec_vector_binary(mach, inst, micro_xor, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_SAD: |
assert (0); |
break; |
case TGSI_OPCODE_TXF: |
exec_txf(mach, inst); |
break; |
case TGSI_OPCODE_TXQ: |
exec_txq(mach, inst); |
break; |
case TGSI_OPCODE_EMIT: |
emit_vertex(mach); |
break; |
case TGSI_OPCODE_ENDPRIM: |
emit_primitive(mach); |
break; |
case TGSI_OPCODE_BGNLOOP: |
/* push LoopMask and ContMasks */ |
assert(mach->LoopStackTop < TGSI_EXEC_MAX_LOOP_NESTING); |
assert(mach->ContStackTop < TGSI_EXEC_MAX_LOOP_NESTING); |
assert(mach->LoopLabelStackTop < TGSI_EXEC_MAX_LOOP_NESTING); |
assert(mach->BreakStackTop < TGSI_EXEC_MAX_BREAK_STACK); |
mach->LoopStack[mach->LoopStackTop++] = mach->LoopMask; |
mach->ContStack[mach->ContStackTop++] = mach->ContMask; |
mach->LoopLabelStack[mach->LoopLabelStackTop++] = *pc - 1; |
mach->BreakStack[mach->BreakStackTop++] = mach->BreakType; |
mach->BreakType = TGSI_EXEC_BREAK_INSIDE_LOOP; |
break; |
case TGSI_OPCODE_ENDLOOP: |
/* Restore ContMask, but don't pop */ |
assert(mach->ContStackTop > 0); |
mach->ContMask = mach->ContStack[mach->ContStackTop - 1]; |
UPDATE_EXEC_MASK(mach); |
if (mach->ExecMask) { |
/* repeat loop: jump to instruction just past BGNLOOP */ |
assert(mach->LoopLabelStackTop > 0); |
*pc = mach->LoopLabelStack[mach->LoopLabelStackTop - 1] + 1; |
} |
else { |
/* exit loop: pop LoopMask */ |
assert(mach->LoopStackTop > 0); |
mach->LoopMask = mach->LoopStack[--mach->LoopStackTop]; |
/* pop ContMask */ |
assert(mach->ContStackTop > 0); |
mach->ContMask = mach->ContStack[--mach->ContStackTop]; |
assert(mach->LoopLabelStackTop > 0); |
--mach->LoopLabelStackTop; |
mach->BreakType = mach->BreakStack[--mach->BreakStackTop]; |
} |
UPDATE_EXEC_MASK(mach); |
break; |
case TGSI_OPCODE_BRK: |
exec_break(mach); |
break; |
case TGSI_OPCODE_CONT: |
/* turn off cont channels for each enabled exec channel */ |
mach->ContMask &= ~mach->ExecMask; |
/* Todo: if mach->LoopMask == 0, jump to end of loop */ |
UPDATE_EXEC_MASK(mach); |
break; |
case TGSI_OPCODE_BGNSUB: |
/* no-op */ |
break; |
case TGSI_OPCODE_ENDSUB: |
/* |
* XXX: This really should be a no-op. We should never reach this opcode. |
*/ |
assert(mach->CallStackTop > 0); |
mach->CallStackTop--; |
mach->CondStackTop = mach->CallStack[mach->CallStackTop].CondStackTop; |
mach->CondMask = mach->CondStack[mach->CondStackTop]; |
mach->LoopStackTop = mach->CallStack[mach->CallStackTop].LoopStackTop; |
mach->LoopMask = mach->LoopStack[mach->LoopStackTop]; |
mach->ContStackTop = mach->CallStack[mach->CallStackTop].ContStackTop; |
mach->ContMask = mach->ContStack[mach->ContStackTop]; |
mach->SwitchStackTop = mach->CallStack[mach->CallStackTop].SwitchStackTop; |
mach->Switch = mach->SwitchStack[mach->SwitchStackTop]; |
mach->BreakStackTop = mach->CallStack[mach->CallStackTop].BreakStackTop; |
mach->BreakType = mach->BreakStack[mach->BreakStackTop]; |
assert(mach->FuncStackTop > 0); |
mach->FuncMask = mach->FuncStack[--mach->FuncStackTop]; |
*pc = mach->CallStack[mach->CallStackTop].ReturnAddr; |
UPDATE_EXEC_MASK(mach); |
break; |
case TGSI_OPCODE_NOP: |
break; |
case TGSI_OPCODE_BREAKC: |
IFETCH(&r[0], 0, TGSI_CHAN_X); |
/* update CondMask */ |
if (r[0].u[0] && (mach->ExecMask & 0x1)) { |
mach->LoopMask &= ~0x1; |
} |
if (r[0].u[1] && (mach->ExecMask & 0x2)) { |
mach->LoopMask &= ~0x2; |
} |
if (r[0].u[2] && (mach->ExecMask & 0x4)) { |
mach->LoopMask &= ~0x4; |
} |
if (r[0].u[3] && (mach->ExecMask & 0x8)) { |
mach->LoopMask &= ~0x8; |
} |
/* Todo: if mach->LoopMask == 0, jump to end of loop */ |
UPDATE_EXEC_MASK(mach); |
break; |
case TGSI_OPCODE_F2I: |
exec_vector_unary(mach, inst, micro_f2i, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_IDIV: |
exec_vector_binary(mach, inst, micro_idiv, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); |
break; |
case TGSI_OPCODE_IMAX: |
exec_vector_binary(mach, inst, micro_imax, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); |
break; |
case TGSI_OPCODE_IMIN: |
exec_vector_binary(mach, inst, micro_imin, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); |
break; |
case TGSI_OPCODE_INEG: |
exec_vector_unary(mach, inst, micro_ineg, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); |
break; |
case TGSI_OPCODE_ISGE: |
exec_vector_binary(mach, inst, micro_isge, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); |
break; |
case TGSI_OPCODE_ISHR: |
exec_vector_binary(mach, inst, micro_ishr, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); |
break; |
case TGSI_OPCODE_ISLT: |
exec_vector_binary(mach, inst, micro_islt, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); |
break; |
case TGSI_OPCODE_F2U: |
exec_vector_unary(mach, inst, micro_f2u, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_FLOAT); |
break; |
case TGSI_OPCODE_U2F: |
exec_vector_unary(mach, inst, micro_u2f, TGSI_EXEC_DATA_FLOAT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_UADD: |
exec_vector_binary(mach, inst, micro_uadd, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); |
break; |
case TGSI_OPCODE_UDIV: |
exec_vector_binary(mach, inst, micro_udiv, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_UMAD: |
exec_vector_trinary(mach, inst, micro_umad, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_UMAX: |
exec_vector_binary(mach, inst, micro_umax, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_UMIN: |
exec_vector_binary(mach, inst, micro_umin, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_UMOD: |
exec_vector_binary(mach, inst, micro_umod, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_UMUL: |
exec_vector_binary(mach, inst, micro_umul, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_USEQ: |
exec_vector_binary(mach, inst, micro_useq, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_USGE: |
exec_vector_binary(mach, inst, micro_usge, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_USHR: |
exec_vector_binary(mach, inst, micro_ushr, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_USLT: |
exec_vector_binary(mach, inst, micro_uslt, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_USNE: |
exec_vector_binary(mach, inst, micro_usne, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_SWITCH: |
exec_switch(mach, inst); |
break; |
case TGSI_OPCODE_CASE: |
exec_case(mach, inst); |
break; |
case TGSI_OPCODE_DEFAULT: |
exec_default(mach); |
break; |
case TGSI_OPCODE_ENDSWITCH: |
exec_endswitch(mach); |
break; |
case TGSI_OPCODE_SAMPLE_I: |
exec_txf(mach, inst); |
break; |
case TGSI_OPCODE_SAMPLE_I_MS: |
assert(0); |
break; |
case TGSI_OPCODE_SAMPLE: |
exec_sample(mach, inst, TEX_MODIFIER_NONE, FALSE); |
break; |
case TGSI_OPCODE_SAMPLE_B: |
exec_sample(mach, inst, TEX_MODIFIER_LOD_BIAS, FALSE); |
break; |
case TGSI_OPCODE_SAMPLE_C: |
exec_sample(mach, inst, TEX_MODIFIER_NONE, TRUE); |
break; |
case TGSI_OPCODE_SAMPLE_C_LZ: |
exec_sample(mach, inst, TEX_MODIFIER_LEVEL_ZERO, TRUE); |
break; |
case TGSI_OPCODE_SAMPLE_D: |
exec_sample_d(mach, inst); |
break; |
case TGSI_OPCODE_SAMPLE_L: |
exec_sample(mach, inst, TEX_MODIFIER_EXPLICIT_LOD, FALSE); |
break; |
case TGSI_OPCODE_GATHER4: |
assert(0); |
break; |
case TGSI_OPCODE_SVIEWINFO: |
exec_txq(mach, inst); |
break; |
case TGSI_OPCODE_SAMPLE_POS: |
assert(0); |
break; |
case TGSI_OPCODE_SAMPLE_INFO: |
assert(0); |
break; |
case TGSI_OPCODE_UARL: |
exec_vector_unary(mach, inst, micro_uarl, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_UCMP: |
exec_vector_trinary(mach, inst, micro_ucmp, TGSI_EXEC_DATA_UINT, TGSI_EXEC_DATA_UINT); |
break; |
case TGSI_OPCODE_IABS: |
exec_vector_unary(mach, inst, micro_iabs, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); |
break; |
case TGSI_OPCODE_ISSG: |
exec_vector_unary(mach, inst, micro_isgn, TGSI_EXEC_DATA_INT, TGSI_EXEC_DATA_INT); |
break; |
case TGSI_OPCODE_TEX2: |
/* simple texture lookup */ |
/* src[0] = texcoord */ |
/* src[1] = compare */ |
/* src[2] = sampler unit */ |
exec_tex(mach, inst, TEX_MODIFIER_NONE, 2); |
break; |
case TGSI_OPCODE_TXB2: |
/* simple texture lookup */ |
/* src[0] = texcoord */ |
/* src[1] = bias */ |
/* src[2] = sampler unit */ |
exec_tex(mach, inst, TEX_MODIFIER_LOD_BIAS, 2); |
break; |
case TGSI_OPCODE_TXL2: |
/* simple texture lookup */ |
/* src[0] = texcoord */ |
/* src[1] = lod */ |
/* src[2] = sampler unit */ |
exec_tex(mach, inst, TEX_MODIFIER_EXPLICIT_LOD, 2); |
break; |
default: |
assert( 0 ); |
} |
} |
/** |
* Run TGSI interpreter. |
* \return bitmask of "alive" quad components |
*/ |
uint |
tgsi_exec_machine_run( struct tgsi_exec_machine *mach ) |
{ |
uint i; |
int pc = 0; |
uint default_mask = 0xf; |
mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0] = 0; |
mach->Temps[TEMP_OUTPUT_I].xyzw[TEMP_OUTPUT_C].u[0] = 0; |
if( mach->Processor == TGSI_PROCESSOR_GEOMETRY ) { |
mach->Temps[TEMP_PRIMITIVE_I].xyzw[TEMP_PRIMITIVE_C].u[0] = 0; |
mach->Primitives[0] = 0; |
/* GS runs on a single primitive for now */ |
default_mask = 0x1; |
} |
mach->CondMask = default_mask; |
mach->LoopMask = default_mask; |
mach->ContMask = default_mask; |
mach->FuncMask = default_mask; |
mach->ExecMask = default_mask; |
mach->Switch.mask = default_mask; |
assert(mach->CondStackTop == 0); |
assert(mach->LoopStackTop == 0); |
assert(mach->ContStackTop == 0); |
assert(mach->SwitchStackTop == 0); |
assert(mach->BreakStackTop == 0); |
assert(mach->CallStackTop == 0); |
/* execute declarations (interpolants) */ |
for (i = 0; i < mach->NumDeclarations; i++) { |
exec_declaration( mach, mach->Declarations+i ); |
} |
{ |
#if DEBUG_EXECUTION |
struct tgsi_exec_vector temps[TGSI_EXEC_NUM_TEMPS + TGSI_EXEC_NUM_TEMP_EXTRAS]; |
struct tgsi_exec_vector outputs[PIPE_MAX_ATTRIBS]; |
uint inst = 1; |
memset(mach->Temps, 0, sizeof(temps)); |
memset(mach->Outputs, 0, sizeof(outputs)); |
memset(temps, 0, sizeof(temps)); |
memset(outputs, 0, sizeof(outputs)); |
#endif |
/* execute instructions, until pc is set to -1 */ |
while (pc != -1) { |
#if DEBUG_EXECUTION |
uint i; |
tgsi_dump_instruction(&mach->Instructions[pc], inst++); |
#endif |
assert(pc < (int) mach->NumInstructions); |
exec_instruction(mach, mach->Instructions + pc, &pc); |
#if DEBUG_EXECUTION |
for (i = 0; i < TGSI_EXEC_NUM_TEMPS + TGSI_EXEC_NUM_TEMP_EXTRAS; i++) { |
if (memcmp(&temps[i], &mach->Temps[i], sizeof(temps[i]))) { |
uint j; |
memcpy(&temps[i], &mach->Temps[i], sizeof(temps[i])); |
debug_printf("TEMP[%2u] = ", i); |
for (j = 0; j < 4; j++) { |
if (j > 0) { |
debug_printf(" "); |
} |
debug_printf("(%6f %u, %6f %u, %6f %u, %6f %u)\n", |
temps[i].xyzw[0].f[j], temps[i].xyzw[0].u[j], |
temps[i].xyzw[1].f[j], temps[i].xyzw[1].u[j], |
temps[i].xyzw[2].f[j], temps[i].xyzw[2].u[j], |
temps[i].xyzw[3].f[j], temps[i].xyzw[3].u[j]); |
} |
} |
} |
for (i = 0; i < PIPE_MAX_ATTRIBS; i++) { |
if (memcmp(&outputs[i], &mach->Outputs[i], sizeof(outputs[i]))) { |
uint j; |
memcpy(&outputs[i], &mach->Outputs[i], sizeof(outputs[i])); |
debug_printf("OUT[%2u] = ", i); |
for (j = 0; j < 4; j++) { |
if (j > 0) { |
debug_printf(" "); |
} |
debug_printf("(%6f %u, %6f %u, %6f %u, %6f %u)\n", |
outputs[i].xyzw[0].f[j], outputs[i].xyzw[0].u[j], |
outputs[i].xyzw[1].f[j], outputs[i].xyzw[1].u[j], |
outputs[i].xyzw[2].f[j], outputs[i].xyzw[2].u[j], |
outputs[i].xyzw[3].f[j], outputs[i].xyzw[3].u[j]); |
} |
} |
} |
#endif |
} |
} |
#if 0 |
/* we scale from floats in [0,1] to Zbuffer ints in sp_quad_depth_test.c */ |
if (mach->Processor == TGSI_PROCESSOR_FRAGMENT) { |
/* |
* Scale back depth component. |
*/ |
for (i = 0; i < 4; i++) |
mach->Outputs[0].xyzw[2].f[i] *= ctx->DrawBuffer->_DepthMaxF; |
} |
#endif |
/* Strictly speaking, these assertions aren't really needed but they |
* can potentially catch some bugs in the control flow code. |
*/ |
assert(mach->CondStackTop == 0); |
assert(mach->LoopStackTop == 0); |
assert(mach->ContStackTop == 0); |
assert(mach->SwitchStackTop == 0); |
assert(mach->BreakStackTop == 0); |
assert(mach->CallStackTop == 0); |
return ~mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0]; |
} |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_exec.h |
---|
0,0 → 1,463 |
/************************************************************************** |
* |
* Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. |
* All Rights Reserved. |
* Copyright 2009-2010 VMware, Inc. 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. |
* |
**************************************************************************/ |
#ifndef TGSI_EXEC_H |
#define TGSI_EXEC_H |
#include "pipe/p_compiler.h" |
#include "pipe/p_state.h" |
#include "pipe/p_shader_tokens.h" |
#if defined __cplusplus |
extern "C" { |
#endif |
#define TGSI_CHAN_X 0 |
#define TGSI_CHAN_Y 1 |
#define TGSI_CHAN_Z 2 |
#define TGSI_CHAN_W 3 |
#define TGSI_NUM_CHANNELS 4 /* R,G,B,A */ |
#define TGSI_QUAD_SIZE 4 /* 4 pixel/quad */ |
#define TGSI_FOR_EACH_CHANNEL( CHAN )\ |
for (CHAN = 0; CHAN < TGSI_NUM_CHANNELS; CHAN++) |
#define TGSI_IS_DST0_CHANNEL_ENABLED( INST, CHAN )\ |
((INST)->Dst[0].Register.WriteMask & (1 << (CHAN))) |
#define TGSI_IF_IS_DST0_CHANNEL_ENABLED( INST, CHAN )\ |
if (TGSI_IS_DST0_CHANNEL_ENABLED( INST, CHAN )) |
#define TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( INST, CHAN )\ |
TGSI_FOR_EACH_CHANNEL( CHAN )\ |
TGSI_IF_IS_DST0_CHANNEL_ENABLED( INST, CHAN ) |
/** |
* Registers may be treated as float, signed int or unsigned int. |
*/ |
union tgsi_exec_channel |
{ |
float f[TGSI_QUAD_SIZE]; |
int i[TGSI_QUAD_SIZE]; |
unsigned u[TGSI_QUAD_SIZE]; |
}; |
/** |
* A vector[RGBA] of channels[4 pixels] |
*/ |
struct tgsi_exec_vector |
{ |
union tgsi_exec_channel xyzw[TGSI_NUM_CHANNELS]; |
}; |
/** |
* For fragment programs, information for computing fragment input |
* values from plane equation of the triangle/line. |
*/ |
struct tgsi_interp_coef |
{ |
float a0[TGSI_NUM_CHANNELS]; /* in an xyzw layout */ |
float dadx[TGSI_NUM_CHANNELS]; |
float dady[TGSI_NUM_CHANNELS]; |
}; |
enum tgsi_sampler_control { |
tgsi_sampler_lod_none, |
tgsi_sampler_lod_bias, |
tgsi_sampler_lod_explicit, |
tgsi_sampler_lod_zero, |
tgsi_sampler_derivs_explicit |
}; |
/** |
* Information for sampling textures, which must be implemented |
* by code outside the TGSI executor. |
*/ |
struct tgsi_sampler |
{ |
/** Get samples for four fragments in a quad */ |
/* this interface contains 5 sets of channels that vary |
* depending on the sampler. |
* s - the first texture coordinate for sampling. |
* t - the second texture coordinate for sampling - unused for 1D, |
layer for 1D arrays. |
* r - the third coordinate for sampling for 3D, cube, cube arrays, |
* layer for 2D arrays. Compare value for 1D/2D shadows. |
* c0 - Compare value for shadow cube and shadow 2d arrays, |
* layer for cube arrays. |
* derivs - explicit derivatives. |
* offset - texel offsets |
* lod - lod value, except for shadow cube arrays (compare value there). |
*/ |
void (*get_samples)(struct tgsi_sampler *sampler, |
const unsigned sview_index, |
const unsigned sampler_index, |
const float s[TGSI_QUAD_SIZE], |
const float t[TGSI_QUAD_SIZE], |
const float r[TGSI_QUAD_SIZE], |
const float c0[TGSI_QUAD_SIZE], |
const float c1[TGSI_QUAD_SIZE], |
float derivs[3][2][TGSI_QUAD_SIZE], |
const int8_t offset[3], |
enum tgsi_sampler_control control, |
float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]); |
void (*get_dims)(struct tgsi_sampler *sampler, |
const unsigned sview_index, |
int level, int dims[4]); |
void (*get_texel)(struct tgsi_sampler *sampler, |
const unsigned sview_index, |
const int i[TGSI_QUAD_SIZE], |
const int j[TGSI_QUAD_SIZE], const int k[TGSI_QUAD_SIZE], |
const int lod[TGSI_QUAD_SIZE], const int8_t offset[3], |
float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]); |
}; |
#define TGSI_EXEC_NUM_TEMPS 4096 |
#define TGSI_EXEC_NUM_IMMEDIATES 256 |
/* |
* Locations of various utility registers (_I = Index, _C = Channel) |
*/ |
#define TGSI_EXEC_TEMP_00000000_I (TGSI_EXEC_NUM_TEMPS + 0) |
#define TGSI_EXEC_TEMP_00000000_C 0 |
#define TGSI_EXEC_TEMP_7FFFFFFF_I (TGSI_EXEC_NUM_TEMPS + 0) |
#define TGSI_EXEC_TEMP_7FFFFFFF_C 1 |
#define TGSI_EXEC_TEMP_80000000_I (TGSI_EXEC_NUM_TEMPS + 0) |
#define TGSI_EXEC_TEMP_80000000_C 2 |
#define TGSI_EXEC_TEMP_FFFFFFFF_I (TGSI_EXEC_NUM_TEMPS + 0) |
#define TGSI_EXEC_TEMP_FFFFFFFF_C 3 |
#define TGSI_EXEC_TEMP_ONE_I (TGSI_EXEC_NUM_TEMPS + 1) |
#define TGSI_EXEC_TEMP_ONE_C 0 |
#define TGSI_EXEC_TEMP_TWO_I (TGSI_EXEC_NUM_TEMPS + 1) |
#define TGSI_EXEC_TEMP_TWO_C 1 |
#define TGSI_EXEC_TEMP_128_I (TGSI_EXEC_NUM_TEMPS + 1) |
#define TGSI_EXEC_TEMP_128_C 2 |
#define TGSI_EXEC_TEMP_MINUS_128_I (TGSI_EXEC_NUM_TEMPS + 1) |
#define TGSI_EXEC_TEMP_MINUS_128_C 3 |
#define TGSI_EXEC_TEMP_KILMASK_I (TGSI_EXEC_NUM_TEMPS + 2) |
#define TGSI_EXEC_TEMP_KILMASK_C 0 |
#define TGSI_EXEC_TEMP_OUTPUT_I (TGSI_EXEC_NUM_TEMPS + 2) |
#define TGSI_EXEC_TEMP_OUTPUT_C 1 |
#define TGSI_EXEC_TEMP_PRIMITIVE_I (TGSI_EXEC_NUM_TEMPS + 2) |
#define TGSI_EXEC_TEMP_PRIMITIVE_C 2 |
#define TGSI_EXEC_TEMP_THREE_I (TGSI_EXEC_NUM_TEMPS + 2) |
#define TGSI_EXEC_TEMP_THREE_C 3 |
#define TGSI_EXEC_TEMP_HALF_I (TGSI_EXEC_NUM_TEMPS + 3) |
#define TGSI_EXEC_TEMP_HALF_C 0 |
/* execution mask, each value is either 0 or ~0 */ |
#define TGSI_EXEC_MASK_I (TGSI_EXEC_NUM_TEMPS + 3) |
#define TGSI_EXEC_MASK_C 1 |
/* 4 register buffer for various purposes */ |
#define TGSI_EXEC_TEMP_R0 (TGSI_EXEC_NUM_TEMPS + 4) |
#define TGSI_EXEC_NUM_TEMP_R 4 |
#define TGSI_EXEC_TEMP_ADDR (TGSI_EXEC_NUM_TEMPS + 8) |
#define TGSI_EXEC_NUM_ADDRS 1 |
/* predicate register */ |
#define TGSI_EXEC_TEMP_P0 (TGSI_EXEC_NUM_TEMPS + 9) |
#define TGSI_EXEC_NUM_PREDS 1 |
#define TGSI_EXEC_NUM_TEMP_EXTRAS 10 |
#define TGSI_EXEC_MAX_NESTING 32 |
#define TGSI_EXEC_MAX_COND_NESTING TGSI_EXEC_MAX_NESTING |
#define TGSI_EXEC_MAX_LOOP_NESTING TGSI_EXEC_MAX_NESTING |
#define TGSI_EXEC_MAX_SWITCH_NESTING TGSI_EXEC_MAX_NESTING |
#define TGSI_EXEC_MAX_CALL_NESTING TGSI_EXEC_MAX_NESTING |
/* The maximum number of input attributes per vertex. For 2D |
* input register files, this is the stride between two 1D |
* arrays. |
*/ |
#define TGSI_EXEC_MAX_INPUT_ATTRIBS 17 |
/* The maximum number of constant vectors per constant buffer. |
*/ |
#define TGSI_EXEC_MAX_CONST_BUFFER 4096 |
/* The maximum number of vertices per primitive */ |
#define TGSI_MAX_PRIM_VERTICES 6 |
/* The maximum number of primitives to be generated */ |
#define TGSI_MAX_PRIMITIVES 64 |
/* The maximum total number of vertices */ |
#define TGSI_MAX_TOTAL_VERTICES (TGSI_MAX_PRIM_VERTICES * TGSI_MAX_PRIMITIVES * PIPE_MAX_ATTRIBS) |
#define TGSI_MAX_MISC_INPUTS 8 |
/** function call/activation record */ |
struct tgsi_call_record |
{ |
uint CondStackTop; |
uint LoopStackTop; |
uint ContStackTop; |
int SwitchStackTop; |
int BreakStackTop; |
uint ReturnAddr; |
}; |
/* Switch-case block state. */ |
struct tgsi_switch_record { |
uint mask; /**< execution mask */ |
union tgsi_exec_channel selector; /**< a value case statements are compared to */ |
uint defaultMask; /**< non-execute mask for default case */ |
}; |
enum tgsi_break_type { |
TGSI_EXEC_BREAK_INSIDE_LOOP, |
TGSI_EXEC_BREAK_INSIDE_SWITCH |
}; |
#define TGSI_EXEC_MAX_BREAK_STACK (TGSI_EXEC_MAX_LOOP_NESTING + TGSI_EXEC_MAX_SWITCH_NESTING) |
/** |
* Run-time virtual machine state for executing TGSI shader. |
*/ |
struct tgsi_exec_machine |
{ |
/* Total = program temporaries + internal temporaries |
*/ |
struct tgsi_exec_vector Temps[TGSI_EXEC_NUM_TEMPS + |
TGSI_EXEC_NUM_TEMP_EXTRAS]; |
float Imms[TGSI_EXEC_NUM_IMMEDIATES][4]; |
float ImmArray[TGSI_EXEC_NUM_IMMEDIATES][4]; |
struct tgsi_exec_vector *Inputs; |
struct tgsi_exec_vector *Outputs; |
/* System values */ |
unsigned SysSemanticToIndex[TGSI_SEMANTIC_COUNT]; |
union tgsi_exec_channel SystemValue[TGSI_MAX_MISC_INPUTS]; |
struct tgsi_exec_vector *Addrs; |
struct tgsi_exec_vector *Predicates; |
struct tgsi_sampler *Sampler; |
unsigned ImmLimit; |
const void *Consts[PIPE_MAX_CONSTANT_BUFFERS]; |
unsigned ConstsSize[PIPE_MAX_CONSTANT_BUFFERS]; |
const struct tgsi_token *Tokens; /**< Declarations, instructions */ |
unsigned Processor; /**< TGSI_PROCESSOR_x */ |
/* GEOMETRY processor only. */ |
unsigned *Primitives; |
unsigned NumOutputs; |
unsigned MaxGeometryShaderOutputs; |
/* FRAGMENT processor only. */ |
const struct tgsi_interp_coef *InterpCoefs; |
struct tgsi_exec_vector QuadPos; |
float Face; /**< +1 if front facing, -1 if back facing */ |
bool flatshade_color; |
/* Conditional execution masks */ |
uint CondMask; /**< For IF/ELSE/ENDIF */ |
uint LoopMask; /**< For BGNLOOP/ENDLOOP */ |
uint ContMask; /**< For loop CONT statements */ |
uint FuncMask; /**< For function calls */ |
uint ExecMask; /**< = CondMask & LoopMask */ |
/* Current switch-case state. */ |
struct tgsi_switch_record Switch; |
/* Current break type. */ |
enum tgsi_break_type BreakType; |
/** Condition mask stack (for nested conditionals) */ |
uint CondStack[TGSI_EXEC_MAX_COND_NESTING]; |
int CondStackTop; |
/** Loop mask stack (for nested loops) */ |
uint LoopStack[TGSI_EXEC_MAX_LOOP_NESTING]; |
int LoopStackTop; |
/** Loop label stack */ |
uint LoopLabelStack[TGSI_EXEC_MAX_LOOP_NESTING]; |
int LoopLabelStackTop; |
/** Loop continue mask stack (see comments in tgsi_exec.c) */ |
uint ContStack[TGSI_EXEC_MAX_LOOP_NESTING]; |
int ContStackTop; |
/** Switch case stack */ |
struct tgsi_switch_record SwitchStack[TGSI_EXEC_MAX_SWITCH_NESTING]; |
int SwitchStackTop; |
enum tgsi_break_type BreakStack[TGSI_EXEC_MAX_BREAK_STACK]; |
int BreakStackTop; |
/** Function execution mask stack (for executing subroutine code) */ |
uint FuncStack[TGSI_EXEC_MAX_CALL_NESTING]; |
int FuncStackTop; |
/** Function call stack for saving/restoring the program counter */ |
struct tgsi_call_record CallStack[TGSI_EXEC_MAX_CALL_NESTING]; |
int CallStackTop; |
struct tgsi_full_instruction *Instructions; |
uint NumInstructions; |
struct tgsi_full_declaration *Declarations; |
uint NumDeclarations; |
struct tgsi_declaration_sampler_view |
SamplerViews[PIPE_MAX_SHADER_SAMPLER_VIEWS]; |
boolean UsedGeometryShader; |
}; |
struct tgsi_exec_machine * |
tgsi_exec_machine_create( void ); |
void |
tgsi_exec_machine_destroy(struct tgsi_exec_machine *mach); |
void |
tgsi_exec_machine_bind_shader( |
struct tgsi_exec_machine *mach, |
const struct tgsi_token *tokens, |
struct tgsi_sampler *sampler); |
uint |
tgsi_exec_machine_run( |
struct tgsi_exec_machine *mach ); |
void |
tgsi_exec_machine_free_data(struct tgsi_exec_machine *mach); |
boolean |
tgsi_check_soa_dependencies(const struct tgsi_full_instruction *inst); |
static INLINE void |
tgsi_set_kill_mask(struct tgsi_exec_machine *mach, unsigned mask) |
{ |
mach->Temps[TGSI_EXEC_TEMP_KILMASK_I].xyzw[TGSI_EXEC_TEMP_KILMASK_C].u[0] = |
mask; |
} |
/** Set execution mask values prior to executing the shader */ |
static INLINE void |
tgsi_set_exec_mask(struct tgsi_exec_machine *mach, |
boolean ch0, boolean ch1, boolean ch2, boolean ch3) |
{ |
int *mask = mach->Temps[TGSI_EXEC_MASK_I].xyzw[TGSI_EXEC_MASK_C].i; |
mask[0] = ch0 ? ~0 : 0; |
mask[1] = ch1 ? ~0 : 0; |
mask[2] = ch2 ? ~0 : 0; |
mask[3] = ch3 ? ~0 : 0; |
} |
extern void |
tgsi_exec_set_constant_buffers(struct tgsi_exec_machine *mach, |
unsigned num_bufs, |
const void **bufs, |
const unsigned *buf_sizes); |
static INLINE int |
tgsi_exec_get_shader_param(enum pipe_shader_cap param) |
{ |
switch(param) { |
case PIPE_SHADER_CAP_MAX_INSTRUCTIONS: |
case PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS: |
case PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS: |
case PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS: |
return INT_MAX; |
case PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH: |
return TGSI_EXEC_MAX_NESTING; |
case PIPE_SHADER_CAP_MAX_INPUTS: |
return TGSI_EXEC_MAX_INPUT_ATTRIBS; |
case PIPE_SHADER_CAP_MAX_CONSTS: |
return TGSI_EXEC_MAX_CONST_BUFFER; |
case PIPE_SHADER_CAP_MAX_CONST_BUFFERS: |
return PIPE_MAX_CONSTANT_BUFFERS; |
case PIPE_SHADER_CAP_MAX_TEMPS: |
return TGSI_EXEC_NUM_TEMPS; |
case PIPE_SHADER_CAP_MAX_ADDRS: |
return TGSI_EXEC_NUM_ADDRS; |
case PIPE_SHADER_CAP_MAX_PREDS: |
return TGSI_EXEC_NUM_PREDS; |
case PIPE_SHADER_CAP_TGSI_CONT_SUPPORTED: |
return 1; |
case PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR: |
case PIPE_SHADER_CAP_INDIRECT_OUTPUT_ADDR: |
case PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR: |
case PIPE_SHADER_CAP_INDIRECT_CONST_ADDR: |
return 1; |
case PIPE_SHADER_CAP_SUBROUTINES: |
return 1; |
case PIPE_SHADER_CAP_INTEGERS: |
return 1; |
case PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS: |
return PIPE_MAX_SAMPLERS; |
case PIPE_SHADER_CAP_TGSI_SQRT_SUPPORTED: |
return 1; |
default: |
return 0; |
} |
} |
#if defined __cplusplus |
} /* extern "C" */ |
#endif |
#endif /* TGSI_EXEC_H */ |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_info.c |
---|
0,0 → 1,360 |
/************************************************************************** |
* |
* Copyright 2008 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 "util/u_debug.h" |
#include "util/u_memory.h" |
#include "tgsi_info.h" |
#define NONE TGSI_OUTPUT_NONE |
#define COMP TGSI_OUTPUT_COMPONENTWISE |
#define REPL TGSI_OUTPUT_REPLICATE |
#define CHAN TGSI_OUTPUT_CHAN_DEPENDENT |
#define OTHR TGSI_OUTPUT_OTHER |
static const struct tgsi_opcode_info opcode_info[TGSI_OPCODE_LAST] = |
{ |
{ 1, 1, 0, 0, 0, 0, COMP, "ARL", TGSI_OPCODE_ARL }, |
{ 1, 1, 0, 0, 0, 0, COMP, "MOV", TGSI_OPCODE_MOV }, |
{ 1, 1, 0, 0, 0, 0, CHAN, "LIT", TGSI_OPCODE_LIT }, |
{ 1, 1, 0, 0, 0, 0, REPL, "RCP", TGSI_OPCODE_RCP }, |
{ 1, 1, 0, 0, 0, 0, REPL, "RSQ", TGSI_OPCODE_RSQ }, |
{ 1, 1, 0, 0, 0, 0, CHAN, "EXP", TGSI_OPCODE_EXP }, |
{ 1, 1, 0, 0, 0, 0, CHAN, "LOG", TGSI_OPCODE_LOG }, |
{ 1, 2, 0, 0, 0, 0, COMP, "MUL", TGSI_OPCODE_MUL }, |
{ 1, 2, 0, 0, 0, 0, COMP, "ADD", TGSI_OPCODE_ADD }, |
{ 1, 2, 0, 0, 0, 0, REPL, "DP3", TGSI_OPCODE_DP3 }, |
{ 1, 2, 0, 0, 0, 0, REPL, "DP4", TGSI_OPCODE_DP4 }, |
{ 1, 2, 0, 0, 0, 0, CHAN, "DST", TGSI_OPCODE_DST }, |
{ 1, 2, 0, 0, 0, 0, COMP, "MIN", TGSI_OPCODE_MIN }, |
{ 1, 2, 0, 0, 0, 0, COMP, "MAX", TGSI_OPCODE_MAX }, |
{ 1, 2, 0, 0, 0, 0, COMP, "SLT", TGSI_OPCODE_SLT }, |
{ 1, 2, 0, 0, 0, 0, COMP, "SGE", TGSI_OPCODE_SGE }, |
{ 1, 3, 0, 0, 0, 0, COMP, "MAD", TGSI_OPCODE_MAD }, |
{ 1, 2, 0, 0, 0, 0, COMP, "SUB", TGSI_OPCODE_SUB }, |
{ 1, 3, 0, 0, 0, 0, COMP, "LRP", TGSI_OPCODE_LRP }, |
{ 1, 3, 0, 0, 0, 0, COMP, "CND", TGSI_OPCODE_CND }, |
{ 1, 1, 0, 0, 0, 0, REPL, "SQRT", TGSI_OPCODE_SQRT }, |
{ 1, 3, 0, 0, 0, 0, REPL, "DP2A", TGSI_OPCODE_DP2A }, |
{ 0, 0, 0, 0, 0, 0, NONE, "", 22 }, /* removed */ |
{ 0, 0, 0, 0, 0, 0, NONE, "", 23 }, /* removed */ |
{ 1, 1, 0, 0, 0, 0, COMP, "FRC", TGSI_OPCODE_FRC }, |
{ 1, 3, 0, 0, 0, 0, COMP, "CLAMP", TGSI_OPCODE_CLAMP }, |
{ 1, 1, 0, 0, 0, 0, COMP, "FLR", TGSI_OPCODE_FLR }, |
{ 1, 1, 0, 0, 0, 0, COMP, "ROUND", TGSI_OPCODE_ROUND }, |
{ 1, 1, 0, 0, 0, 0, REPL, "EX2", TGSI_OPCODE_EX2 }, |
{ 1, 1, 0, 0, 0, 0, REPL, "LG2", TGSI_OPCODE_LG2 }, |
{ 1, 2, 0, 0, 0, 0, REPL, "POW", TGSI_OPCODE_POW }, |
{ 1, 2, 0, 0, 0, 0, COMP, "XPD", TGSI_OPCODE_XPD }, |
{ 0, 0, 0, 0, 0, 0, NONE, "", 32 }, /* removed */ |
{ 1, 1, 0, 0, 0, 0, COMP, "ABS", TGSI_OPCODE_ABS }, |
{ 1, 1, 0, 0, 0, 0, REPL, "RCC", TGSI_OPCODE_RCC }, |
{ 1, 2, 0, 0, 0, 0, REPL, "DPH", TGSI_OPCODE_DPH }, |
{ 1, 1, 0, 0, 0, 0, REPL, "COS", TGSI_OPCODE_COS }, |
{ 1, 1, 0, 0, 0, 0, COMP, "DDX", TGSI_OPCODE_DDX }, |
{ 1, 1, 0, 0, 0, 0, COMP, "DDY", TGSI_OPCODE_DDY }, |
{ 0, 0, 0, 0, 0, 0, NONE, "KILL", TGSI_OPCODE_KILL }, |
{ 1, 1, 0, 0, 0, 0, COMP, "PK2H", TGSI_OPCODE_PK2H }, |
{ 1, 1, 0, 0, 0, 0, COMP, "PK2US", TGSI_OPCODE_PK2US }, |
{ 1, 1, 0, 0, 0, 0, COMP, "PK4B", TGSI_OPCODE_PK4B }, |
{ 1, 1, 0, 0, 0, 0, COMP, "PK4UB", TGSI_OPCODE_PK4UB }, |
{ 1, 2, 0, 0, 0, 0, COMP, "RFL", TGSI_OPCODE_RFL }, |
{ 1, 2, 0, 0, 0, 0, COMP, "SEQ", TGSI_OPCODE_SEQ }, |
{ 1, 2, 0, 0, 0, 0, REPL, "SFL", TGSI_OPCODE_SFL }, |
{ 1, 2, 0, 0, 0, 0, COMP, "SGT", TGSI_OPCODE_SGT }, |
{ 1, 1, 0, 0, 0, 0, REPL, "SIN", TGSI_OPCODE_SIN }, |
{ 1, 2, 0, 0, 0, 0, COMP, "SLE", TGSI_OPCODE_SLE }, |
{ 1, 2, 0, 0, 0, 0, COMP, "SNE", TGSI_OPCODE_SNE }, |
{ 1, 2, 0, 0, 0, 0, REPL, "STR", TGSI_OPCODE_STR }, |
{ 1, 2, 1, 0, 0, 0, OTHR, "TEX", TGSI_OPCODE_TEX }, |
{ 1, 4, 1, 0, 0, 0, OTHR, "TXD", TGSI_OPCODE_TXD }, |
{ 1, 2, 1, 0, 0, 0, OTHR, "TXP", TGSI_OPCODE_TXP }, |
{ 1, 1, 0, 0, 0, 0, COMP, "UP2H", TGSI_OPCODE_UP2H }, |
{ 1, 1, 0, 0, 0, 0, COMP, "UP2US", TGSI_OPCODE_UP2US }, |
{ 1, 1, 0, 0, 0, 0, COMP, "UP4B", TGSI_OPCODE_UP4B }, |
{ 1, 1, 0, 0, 0, 0, COMP, "UP4UB", TGSI_OPCODE_UP4UB }, |
{ 1, 3, 0, 0, 0, 0, COMP, "X2D", TGSI_OPCODE_X2D }, |
{ 1, 1, 0, 0, 0, 0, COMP, "ARA", TGSI_OPCODE_ARA }, |
{ 1, 1, 0, 0, 0, 0, COMP, "ARR", TGSI_OPCODE_ARR }, |
{ 0, 1, 0, 0, 0, 0, NONE, "BRA", TGSI_OPCODE_BRA }, |
{ 0, 0, 0, 1, 0, 0, NONE, "CAL", TGSI_OPCODE_CAL }, |
{ 0, 0, 0, 0, 0, 0, NONE, "RET", TGSI_OPCODE_RET }, |
{ 1, 1, 0, 0, 0, 0, COMP, "SSG", TGSI_OPCODE_SSG }, |
{ 1, 3, 0, 0, 0, 0, COMP, "CMP", TGSI_OPCODE_CMP }, |
{ 1, 1, 0, 0, 0, 0, CHAN, "SCS", TGSI_OPCODE_SCS }, |
{ 1, 2, 1, 0, 0, 0, OTHR, "TXB", TGSI_OPCODE_TXB }, |
{ 1, 1, 0, 0, 0, 0, COMP, "NRM", TGSI_OPCODE_NRM }, |
{ 1, 2, 0, 0, 0, 0, COMP, "DIV", TGSI_OPCODE_DIV }, |
{ 1, 2, 0, 0, 0, 0, REPL, "DP2", TGSI_OPCODE_DP2 }, |
{ 1, 2, 1, 0, 0, 0, OTHR, "TXL", TGSI_OPCODE_TXL }, |
{ 0, 0, 0, 0, 0, 0, NONE, "BRK", TGSI_OPCODE_BRK }, |
{ 0, 1, 0, 1, 0, 1, NONE, "IF", TGSI_OPCODE_IF }, |
{ 0, 1, 0, 1, 0, 1, NONE, "UIF", TGSI_OPCODE_UIF }, |
{ 0, 1, 0, 0, 0, 1, NONE, "", 76 }, /* removed */ |
{ 0, 0, 0, 1, 1, 1, NONE, "ELSE", TGSI_OPCODE_ELSE }, |
{ 0, 0, 0, 0, 1, 0, NONE, "ENDIF", TGSI_OPCODE_ENDIF }, |
{ 1, 0, 0, 0, 1, 0, NONE, "", 79 }, /* removed */ |
{ 0, 0, 0, 0, 1, 0, NONE, "", 80 }, /* removed */ |
{ 0, 1, 0, 0, 0, 0, NONE, "PUSHA", TGSI_OPCODE_PUSHA }, |
{ 1, 0, 0, 0, 0, 0, NONE, "POPA", TGSI_OPCODE_POPA }, |
{ 1, 1, 0, 0, 0, 0, COMP, "CEIL", TGSI_OPCODE_CEIL }, |
{ 1, 1, 0, 0, 0, 0, COMP, "I2F", TGSI_OPCODE_I2F }, |
{ 1, 1, 0, 0, 0, 0, COMP, "NOT", TGSI_OPCODE_NOT }, |
{ 1, 1, 0, 0, 0, 0, COMP, "TRUNC", TGSI_OPCODE_TRUNC }, |
{ 1, 2, 0, 0, 0, 0, COMP, "SHL", TGSI_OPCODE_SHL }, |
{ 0, 0, 0, 0, 0, 0, NONE, "", 88 }, /* removed */ |
{ 1, 2, 0, 0, 0, 0, COMP, "AND", TGSI_OPCODE_AND }, |
{ 1, 2, 0, 0, 0, 0, COMP, "OR", TGSI_OPCODE_OR }, |
{ 1, 2, 0, 0, 0, 0, COMP, "MOD", TGSI_OPCODE_MOD }, |
{ 1, 2, 0, 0, 0, 0, COMP, "XOR", TGSI_OPCODE_XOR }, |
{ 1, 3, 0, 0, 0, 0, COMP, "SAD", TGSI_OPCODE_SAD }, |
{ 1, 2, 1, 0, 0, 0, OTHR, "TXF", TGSI_OPCODE_TXF }, |
{ 1, 2, 1, 0, 0, 0, OTHR, "TXQ", TGSI_OPCODE_TXQ }, |
{ 0, 0, 0, 0, 0, 0, NONE, "CONT", TGSI_OPCODE_CONT }, |
{ 0, 0, 0, 0, 0, 0, NONE, "EMIT", TGSI_OPCODE_EMIT }, |
{ 0, 0, 0, 0, 0, 0, NONE, "ENDPRIM", TGSI_OPCODE_ENDPRIM }, |
{ 0, 0, 0, 1, 0, 1, NONE, "BGNLOOP", TGSI_OPCODE_BGNLOOP }, |
{ 0, 0, 0, 0, 0, 1, NONE, "BGNSUB", TGSI_OPCODE_BGNSUB }, |
{ 0, 0, 0, 1, 1, 0, NONE, "ENDLOOP", TGSI_OPCODE_ENDLOOP }, |
{ 0, 0, 0, 0, 1, 0, NONE, "ENDSUB", TGSI_OPCODE_ENDSUB }, |
{ 1, 1, 1, 0, 0, 0, OTHR, "TXQ_LZ", TGSI_OPCODE_TXQ_LZ }, |
{ 0, 0, 0, 0, 0, 0, NONE, "", 104 }, /* removed */ |
{ 0, 0, 0, 0, 0, 0, NONE, "", 105 }, /* removed */ |
{ 0, 0, 0, 0, 0, 0, NONE, "", 106 }, /* removed */ |
{ 0, 0, 0, 0, 0, 0, NONE, "NOP", TGSI_OPCODE_NOP }, |
{ 0, 0, 0, 0, 0, 0, NONE, "", 108 }, /* removed */ |
{ 0, 0, 0, 0, 0, 0, NONE, "", 109 }, /* removed */ |
{ 0, 0, 0, 0, 0, 0, NONE, "", 110 }, /* removed */ |
{ 0, 0, 0, 0, 0, 0, NONE, "", 111 }, /* removed */ |
{ 1, 1, 0, 0, 0, 0, REPL, "NRM4", TGSI_OPCODE_NRM4 }, |
{ 0, 1, 0, 0, 0, 0, NONE, "CALLNZ", TGSI_OPCODE_CALLNZ }, |
{ 0, 1, 0, 0, 0, 0, NONE, "", 114 }, /* removed */ |
{ 0, 1, 0, 0, 0, 0, NONE, "BREAKC", TGSI_OPCODE_BREAKC }, |
{ 0, 1, 0, 0, 0, 0, NONE, "KILL_IF", TGSI_OPCODE_KILL_IF }, |
{ 0, 0, 0, 0, 0, 0, NONE, "END", TGSI_OPCODE_END }, |
{ 0, 0, 0, 0, 0, 0, NONE, "", 118 }, /* removed */ |
{ 1, 1, 0, 0, 0, 0, COMP, "F2I", TGSI_OPCODE_F2I }, |
{ 1, 2, 0, 0, 0, 0, COMP, "IDIV", TGSI_OPCODE_IDIV }, |
{ 1, 2, 0, 0, 0, 0, COMP, "IMAX", TGSI_OPCODE_IMAX }, |
{ 1, 2, 0, 0, 0, 0, COMP, "IMIN", TGSI_OPCODE_IMIN }, |
{ 1, 1, 0, 0, 0, 0, COMP, "INEG", TGSI_OPCODE_INEG }, |
{ 1, 2, 0, 0, 0, 0, COMP, "ISGE", TGSI_OPCODE_ISGE }, |
{ 1, 2, 0, 0, 0, 0, COMP, "ISHR", TGSI_OPCODE_ISHR }, |
{ 1, 2, 0, 0, 0, 0, COMP, "ISLT", TGSI_OPCODE_ISLT }, |
{ 1, 1, 0, 0, 0, 0, COMP, "F2U", TGSI_OPCODE_F2U }, |
{ 1, 1, 0, 0, 0, 0, COMP, "U2F", TGSI_OPCODE_U2F }, |
{ 1, 2, 0, 0, 0, 0, COMP, "UADD", TGSI_OPCODE_UADD }, |
{ 1, 2, 0, 0, 0, 0, COMP, "UDIV", TGSI_OPCODE_UDIV }, |
{ 1, 3, 0, 0, 0, 0, COMP, "UMAD", TGSI_OPCODE_UMAD }, |
{ 1, 2, 0, 0, 0, 0, COMP, "UMAX", TGSI_OPCODE_UMAX }, |
{ 1, 2, 0, 0, 0, 0, COMP, "UMIN", TGSI_OPCODE_UMIN }, |
{ 1, 2, 0, 0, 0, 0, COMP, "UMOD", TGSI_OPCODE_UMOD }, |
{ 1, 2, 0, 0, 0, 0, COMP, "UMUL", TGSI_OPCODE_UMUL }, |
{ 1, 2, 0, 0, 0, 0, COMP, "USEQ", TGSI_OPCODE_USEQ }, |
{ 1, 2, 0, 0, 0, 0, COMP, "USGE", TGSI_OPCODE_USGE }, |
{ 1, 2, 0, 0, 0, 0, COMP, "USHR", TGSI_OPCODE_USHR }, |
{ 1, 2, 0, 0, 0, 0, COMP, "USLT", TGSI_OPCODE_USLT }, |
{ 1, 2, 0, 0, 0, 0, COMP, "USNE", TGSI_OPCODE_USNE }, |
{ 0, 1, 0, 0, 0, 0, NONE, "SWITCH", TGSI_OPCODE_SWITCH }, |
{ 0, 1, 0, 0, 0, 0, NONE, "CASE", TGSI_OPCODE_CASE }, |
{ 0, 0, 0, 0, 0, 0, NONE, "DEFAULT", TGSI_OPCODE_DEFAULT }, |
{ 0, 0, 0, 0, 0, 0, NONE, "ENDSWITCH", TGSI_OPCODE_ENDSWITCH }, |
{ 1, 3, 0, 0, 0, 0, OTHR, "SAMPLE", TGSI_OPCODE_SAMPLE }, |
{ 1, 2, 0, 0, 0, 0, OTHR, "SAMPLE_I", TGSI_OPCODE_SAMPLE_I }, |
{ 1, 3, 0, 0, 0, 0, OTHR, "SAMPLE_I_MS", TGSI_OPCODE_SAMPLE_I_MS }, |
{ 1, 4, 0, 0, 0, 0, OTHR, "SAMPLE_B", TGSI_OPCODE_SAMPLE_B }, |
{ 1, 4, 0, 0, 0, 0, OTHR, "SAMPLE_C", TGSI_OPCODE_SAMPLE_C }, |
{ 1, 4, 0, 0, 0, 0, OTHR, "SAMPLE_C_LZ", TGSI_OPCODE_SAMPLE_C_LZ }, |
{ 1, 5, 0, 0, 0, 0, OTHR, "SAMPLE_D", TGSI_OPCODE_SAMPLE_D }, |
{ 1, 4, 0, 0, 0, 0, OTHR, "SAMPLE_L", TGSI_OPCODE_SAMPLE_L }, |
{ 1, 3, 0, 0, 0, 0, OTHR, "GATHER4", TGSI_OPCODE_GATHER4 }, |
{ 1, 2, 0, 0, 0, 0, OTHR, "SVIEWINFO", TGSI_OPCODE_SVIEWINFO }, |
{ 1, 2, 0, 0, 0, 0, OTHR, "SAMPLE_POS", TGSI_OPCODE_SAMPLE_POS }, |
{ 1, 2, 0, 0, 0, 0, OTHR, "SAMPLE_INFO", TGSI_OPCODE_SAMPLE_INFO }, |
{ 1, 1, 0, 0, 0, 0, COMP, "UARL", TGSI_OPCODE_UARL }, |
{ 1, 3, 0, 0, 0, 0, COMP, "UCMP", TGSI_OPCODE_UCMP }, |
{ 1, 1, 0, 0, 0, 0, COMP, "IABS", TGSI_OPCODE_IABS }, |
{ 1, 1, 0, 0, 0, 0, COMP, "ISSG", TGSI_OPCODE_ISSG }, |
{ 1, 2, 0, 0, 0, 0, OTHR, "LOAD", TGSI_OPCODE_LOAD }, |
{ 1, 2, 0, 0, 0, 0, OTHR, "STORE", TGSI_OPCODE_STORE }, |
{ 1, 0, 0, 0, 0, 0, OTHR, "MFENCE", TGSI_OPCODE_MFENCE }, |
{ 1, 0, 0, 0, 0, 0, OTHR, "LFENCE", TGSI_OPCODE_LFENCE }, |
{ 1, 0, 0, 0, 0, 0, OTHR, "SFENCE", TGSI_OPCODE_SFENCE }, |
{ 0, 0, 0, 0, 0, 0, OTHR, "BARRIER", TGSI_OPCODE_BARRIER }, |
{ 1, 3, 0, 0, 0, 0, OTHR, "ATOMUADD", TGSI_OPCODE_ATOMUADD }, |
{ 1, 3, 0, 0, 0, 0, OTHR, "ATOMXCHG", TGSI_OPCODE_ATOMXCHG }, |
{ 1, 4, 0, 0, 0, 0, OTHR, "ATOMCAS", TGSI_OPCODE_ATOMCAS }, |
{ 1, 3, 0, 0, 0, 0, OTHR, "ATOMAND", TGSI_OPCODE_ATOMAND }, |
{ 1, 3, 0, 0, 0, 0, OTHR, "ATOMOR", TGSI_OPCODE_ATOMOR }, |
{ 1, 3, 0, 0, 0, 0, OTHR, "ATOMXOR", TGSI_OPCODE_ATOMXOR }, |
{ 1, 3, 0, 0, 0, 0, OTHR, "ATOMUMIN", TGSI_OPCODE_ATOMUMIN }, |
{ 1, 3, 0, 0, 0, 0, OTHR, "ATOMUMAX", TGSI_OPCODE_ATOMUMAX }, |
{ 1, 3, 0, 0, 0, 0, OTHR, "ATOMIMIN", TGSI_OPCODE_ATOMIMIN }, |
{ 1, 3, 0, 0, 0, 0, OTHR, "ATOMIMAX", TGSI_OPCODE_ATOMIMAX }, |
{ 1, 3, 1, 0, 0, 0, OTHR, "TEX2", TGSI_OPCODE_TEX2 }, |
{ 1, 3, 1, 0, 0, 0, OTHR, "TXB2", TGSI_OPCODE_TXB2 }, |
{ 1, 3, 1, 0, 0, 0, OTHR, "TXL2", TGSI_OPCODE_TXL2 }, |
}; |
const struct tgsi_opcode_info * |
tgsi_get_opcode_info( uint opcode ) |
{ |
static boolean firsttime = 1; |
if (firsttime) { |
unsigned i; |
firsttime = 0; |
for (i = 0; i < Elements(opcode_info); i++) |
assert(opcode_info[i].opcode == i); |
} |
if (opcode < TGSI_OPCODE_LAST) |
return &opcode_info[opcode]; |
assert( 0 ); |
return NULL; |
} |
const char * |
tgsi_get_opcode_name( uint opcode ) |
{ |
const struct tgsi_opcode_info *info = tgsi_get_opcode_info(opcode); |
return info->mnemonic; |
} |
const char * |
tgsi_get_processor_name( uint processor ) |
{ |
switch (processor) { |
case TGSI_PROCESSOR_VERTEX: |
return "vertex shader"; |
case TGSI_PROCESSOR_FRAGMENT: |
return "fragment shader"; |
case TGSI_PROCESSOR_GEOMETRY: |
return "geometry shader"; |
default: |
return "unknown shader type!"; |
} |
} |
/** |
* Infer the type (of the dst) of the opcode. |
* |
* MOV and UCMP is special so return VOID |
*/ |
static INLINE enum tgsi_opcode_type |
tgsi_opcode_infer_type( uint opcode ) |
{ |
switch (opcode) { |
case TGSI_OPCODE_MOV: |
case TGSI_OPCODE_UCMP: |
return TGSI_TYPE_UNTYPED; |
case TGSI_OPCODE_NOT: |
case TGSI_OPCODE_SHL: |
case TGSI_OPCODE_AND: |
case TGSI_OPCODE_OR: |
case TGSI_OPCODE_XOR: |
case TGSI_OPCODE_SAD: /* XXX some src args may be signed for SAD ? */ |
case TGSI_OPCODE_TXQ: |
case TGSI_OPCODE_TXQ_LZ: |
case TGSI_OPCODE_F2U: |
case TGSI_OPCODE_UDIV: |
case TGSI_OPCODE_UMAD: |
case TGSI_OPCODE_UMAX: |
case TGSI_OPCODE_UMIN: |
case TGSI_OPCODE_UMOD: |
case TGSI_OPCODE_UMUL: |
case TGSI_OPCODE_USEQ: |
case TGSI_OPCODE_USGE: |
case TGSI_OPCODE_USHR: |
case TGSI_OPCODE_USLT: |
case TGSI_OPCODE_USNE: |
case TGSI_OPCODE_SVIEWINFO: |
return TGSI_TYPE_UNSIGNED; |
case TGSI_OPCODE_ARL: |
case TGSI_OPCODE_ARR: |
case TGSI_OPCODE_MOD: |
case TGSI_OPCODE_F2I: |
case TGSI_OPCODE_IDIV: |
case TGSI_OPCODE_IMAX: |
case TGSI_OPCODE_IMIN: |
case TGSI_OPCODE_INEG: |
case TGSI_OPCODE_ISGE: |
case TGSI_OPCODE_ISHR: |
case TGSI_OPCODE_ISLT: |
case TGSI_OPCODE_UADD: |
case TGSI_OPCODE_UARL: |
case TGSI_OPCODE_IABS: |
case TGSI_OPCODE_ISSG: |
return TGSI_TYPE_SIGNED; |
default: |
return TGSI_TYPE_FLOAT; |
} |
} |
/* |
* infer the source type of a TGSI opcode. |
*/ |
enum tgsi_opcode_type |
tgsi_opcode_infer_src_type( uint opcode ) |
{ |
switch (opcode) { |
case TGSI_OPCODE_UIF: |
case TGSI_OPCODE_TXF: |
case TGSI_OPCODE_BREAKC: |
case TGSI_OPCODE_U2F: |
case TGSI_OPCODE_UADD: |
case TGSI_OPCODE_SWITCH: |
case TGSI_OPCODE_CASE: |
case TGSI_OPCODE_SAMPLE_I: |
case TGSI_OPCODE_SAMPLE_I_MS: |
return TGSI_TYPE_UNSIGNED; |
case TGSI_OPCODE_I2F: |
return TGSI_TYPE_SIGNED; |
case TGSI_OPCODE_ARL: |
case TGSI_OPCODE_ARR: |
case TGSI_OPCODE_TXQ_LZ: |
case TGSI_OPCODE_F2I: |
case TGSI_OPCODE_F2U: |
case TGSI_OPCODE_UCMP: |
return TGSI_TYPE_FLOAT; |
default: |
return tgsi_opcode_infer_type(opcode); |
} |
} |
/* |
* infer the destination type of a TGSI opcode. |
*/ |
enum tgsi_opcode_type |
tgsi_opcode_infer_dst_type( uint opcode ) |
{ |
return tgsi_opcode_infer_type(opcode); |
} |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_info.h |
---|
0,0 → 1,113 |
/************************************************************************** |
* |
* Copyright 2008 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. |
* |
**************************************************************************/ |
#ifndef TGSI_INFO_H |
#define TGSI_INFO_H |
#include "pipe/p_compiler.h" |
#include "pipe/p_shader_tokens.h" |
#include "util/u_format.h" |
#if defined __cplusplus |
extern "C" { |
#endif |
/* This enum describes how an opcode calculates its result. */ |
enum tgsi_output_mode { |
/** The opcode produces no result. */ |
TGSI_OUTPUT_NONE = 0, |
/** When this opcode writes to a channel of the destination register, |
* it takes as arguments values from the same channel of the source |
* register(s). |
* |
* Example: TGSI_OPCODE_ADD |
*/ |
TGSI_OUTPUT_COMPONENTWISE = 1, |
/** This opcode writes the same value to all enabled channels of the |
* destination register. |
* |
* Example: TGSI_OPCODE_RSQ |
*/ |
TGSI_OUTPUT_REPLICATE = 2, |
/** The operation performed by this opcode is dependent on which channel |
* of the destination register is being written. |
* |
* Example: TGSI_OPCODE_LOG |
*/ |
TGSI_OUTPUT_CHAN_DEPENDENT = 3, |
/** |
* Example: TGSI_OPCODE_TEX |
*/ |
TGSI_OUTPUT_OTHER = 4 |
}; |
struct tgsi_opcode_info |
{ |
unsigned num_dst:3; |
unsigned num_src:3; |
unsigned is_tex:1; |
unsigned is_branch:1; |
int pre_dedent:2; |
int post_indent:2; |
enum tgsi_output_mode output_mode:3; |
const char *mnemonic; |
uint opcode; |
}; |
const struct tgsi_opcode_info * |
tgsi_get_opcode_info( uint opcode ); |
const char * |
tgsi_get_opcode_name( uint opcode ); |
const char * |
tgsi_get_processor_name( uint processor ); |
enum tgsi_opcode_type { |
TGSI_TYPE_UNTYPED, /* for MOV */ |
TGSI_TYPE_VOID, |
TGSI_TYPE_UNSIGNED, |
TGSI_TYPE_SIGNED, |
TGSI_TYPE_FLOAT, |
TGSI_TYPE_DOUBLE |
}; |
enum tgsi_opcode_type |
tgsi_opcode_infer_src_type( uint opcode ); |
enum tgsi_opcode_type |
tgsi_opcode_infer_dst_type( uint opcode ); |
#if defined __cplusplus |
} |
#endif |
#endif /* TGSI_INFO_H */ |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_iterate.c |
---|
0,0 → 1,90 |
/************************************************************************** |
* |
* Copyright 2008 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 "util/u_debug.h" |
#include "tgsi_iterate.h" |
boolean |
tgsi_iterate_shader( |
const struct tgsi_token *tokens, |
struct tgsi_iterate_context *ctx ) |
{ |
struct tgsi_parse_context parse; |
if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) |
return FALSE; |
ctx->processor = parse.FullHeader.Processor; |
if (ctx->prolog) |
if (!ctx->prolog( ctx )) |
goto fail; |
while (!tgsi_parse_end_of_tokens( &parse )) { |
tgsi_parse_token( &parse ); |
switch (parse.FullToken.Token.Type) { |
case TGSI_TOKEN_TYPE_INSTRUCTION: |
if (ctx->iterate_instruction) |
if (!ctx->iterate_instruction( ctx, &parse.FullToken.FullInstruction )) |
goto fail; |
break; |
case TGSI_TOKEN_TYPE_DECLARATION: |
if (ctx->iterate_declaration) |
if (!ctx->iterate_declaration( ctx, &parse.FullToken.FullDeclaration )) |
goto fail; |
break; |
case TGSI_TOKEN_TYPE_IMMEDIATE: |
if (ctx->iterate_immediate) |
if (!ctx->iterate_immediate( ctx, &parse.FullToken.FullImmediate )) |
goto fail; |
break; |
case TGSI_TOKEN_TYPE_PROPERTY: |
if (ctx->iterate_property) |
if (!ctx->iterate_property( ctx, &parse.FullToken.FullProperty )) |
goto fail; |
break; |
default: |
assert( 0 ); |
} |
} |
if (ctx->epilog) |
if (!ctx->epilog( ctx )) |
goto fail; |
tgsi_parse_free( &parse ); |
return TRUE; |
fail: |
tgsi_parse_free( &parse ); |
return FALSE; |
} |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_iterate.h |
---|
0,0 → 1,80 |
/************************************************************************** |
* |
* Copyright 2008 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. |
* |
**************************************************************************/ |
#ifndef TGSI_ITERATE_H |
#define TGSI_ITERATE_H |
#include "pipe/p_shader_tokens.h" |
#include "tgsi/tgsi_parse.h" |
#if defined __cplusplus |
extern "C" { |
#endif |
struct tgsi_iterate_context |
{ |
boolean |
(* prolog)( |
struct tgsi_iterate_context *ctx ); |
boolean |
(* iterate_instruction)( |
struct tgsi_iterate_context *ctx, |
struct tgsi_full_instruction *inst ); |
boolean |
(* iterate_declaration)( |
struct tgsi_iterate_context *ctx, |
struct tgsi_full_declaration *decl ); |
boolean |
(* iterate_immediate)( |
struct tgsi_iterate_context *ctx, |
struct tgsi_full_immediate *imm ); |
boolean |
(* iterate_property)( |
struct tgsi_iterate_context *ctx, |
struct tgsi_full_property *prop ); |
boolean |
(* epilog)( |
struct tgsi_iterate_context *ctx ); |
struct tgsi_processor processor; |
}; |
boolean |
tgsi_iterate_shader( |
const struct tgsi_token *tokens, |
struct tgsi_iterate_context *ctx ); |
#if defined __cplusplus |
} |
#endif |
#endif /* TGSI_ITERATE_H */ |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_opcode_tmp.h |
---|
0,0 → 1,226 |
/************************************************************************** |
* |
* Copyright 2008 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. |
* |
**************************************************************************/ |
#ifndef OP12_TEX |
#define OP12_TEX(a) OP12(a) |
#endif |
#ifndef OP14_TEX |
#define OP14_TEX(a) OP14(a) |
#endif |
#ifndef OP12_SAMPLE |
#define OP12_SAMPLE(a) OP12(a) |
#endif |
#ifndef OP13_SAMPLE |
#define OP13_SAMPLE(a) OP13(a) |
#endif |
#ifndef OP14_SAMPLE |
#define OP14_SAMPLE(a) OP14(a) |
#endif |
#ifndef OP15_SAMPLE |
#define OP15_SAMPLE(a) OP15(a) |
#endif |
#ifndef OP00_LBL |
#define OP00_LBL(a) OP00(a) |
#endif |
#ifndef OP01_LBL |
#define OP01_LBL(a) OP01(a) |
#endif |
OP11(ARL) |
OP11(MOV) |
OP11(LIT) |
OP11(RCP) |
OP11(RSQ) |
OP11(EXP) |
OP11(LOG) |
OP12(MUL) |
OP12(ADD) |
OP12(DP3) |
OP12(DP4) |
OP12(DST) |
OP12(MIN) |
OP12(MAX) |
OP12(SLT) |
OP12(SGE) |
OP13(MAD) |
OP12(SUB) |
OP13(LRP) |
OP13(CND) |
OP11(SQRT) |
OP13(DP2A) |
OP11(FRC) |
OP13(CLAMP) |
OP11(FLR) |
OP11(ROUND) |
OP11(EX2) |
OP11(LG2) |
OP12(POW) |
OP12(XPD) |
OP11(ABS) |
OP11(RCC) |
OP12(DPH) |
OP11(COS) |
OP11(DDX) |
OP11(DDY) |
OP00(KILL) |
OP11(PK2H) |
OP11(PK2US) |
OP11(PK4B) |
OP11(PK4UB) |
OP12(RFL) |
OP12(SEQ) |
OP12(SFL) |
OP12(SGT) |
OP11(SIN) |
OP12(SLE) |
OP12(SNE) |
OP12(STR) |
OP12_TEX(TEX) |
OP14_TEX(TXD) |
OP12_TEX(TXP) |
OP11(UP2H) |
OP11(UP2US) |
OP11(UP4B) |
OP11(UP4UB) |
OP13(X2D) |
OP11(ARA) |
OP11(ARR) |
OP01(BRA) |
OP00_LBL(CAL) |
OP00(RET) |
OP11(SSG) |
OP13(CMP) |
OP11(SCS) |
OP12_TEX(TXB) |
OP11(NRM) |
OP12(DIV) |
OP12(DP2) |
OP12_TEX(TXL) |
OP00(BRK) |
OP01_LBL(IF) |
OP01_LBL(UIF) |
OP00_LBL(ELSE) |
OP00(ENDIF) |
OP01(PUSHA) |
OP10(POPA) |
OP11(CEIL) |
OP11(I2F) |
OP11(NOT) |
OP11(TRUNC) |
OP12(SHL) |
OP12(AND) |
OP12(OR) |
OP12(MOD) |
OP12(XOR) |
OP13(SAD) |
OP12_TEX(TXF) |
OP12_TEX(TXQ) |
OP00(CONT) |
OP00(EMIT) |
OP00(ENDPRIM) |
OP00_LBL(BGNLOOP) |
OP00(BGNSUB) |
OP00_LBL(ENDLOOP) |
OP00(ENDSUB) |
OP00(NOP) |
OP11(NRM4) |
OP01(CALLNZ) |
OP01(BREAKC) |
OP01(KILL_IF) |
OP00(END) |
OP11(F2I) |
OP12(IDIV) |
OP12(IMAX) |
OP12(IMIN) |
OP11(INEG) |
OP12(ISGE) |
OP12(ISHR) |
OP12(ISLT) |
OP11(F2U) |
OP11(U2F) |
OP12(UADD) |
OP12(UDIV) |
OP13(UMAD) |
OP12(UMAX) |
OP12(UMIN) |
OP12(UMOD) |
OP12(UMUL) |
OP12(USEQ) |
OP12(USGE) |
OP12(USHR) |
OP12(USLT) |
OP12(USNE) |
OP01(SWITCH) |
OP01(CASE) |
OP00(DEFAULT) |
OP00(ENDSWITCH) |
OP13_SAMPLE(SAMPLE) |
OP12_SAMPLE(SAMPLE_I) |
OP13_SAMPLE(SAMPLE_I_MS) |
OP14_SAMPLE(SAMPLE_B) |
OP14_SAMPLE(SAMPLE_C) |
OP14_SAMPLE(SAMPLE_C_LZ) |
OP15_SAMPLE(SAMPLE_D) |
OP14_SAMPLE(SAMPLE_L) |
OP13_SAMPLE(GATHER4) |
OP12(SVIEWINFO) |
OP13(SAMPLE_POS) |
OP12(SAMPLE_INFO) |
#undef OP00 |
#undef OP01 |
#undef OP10 |
#undef OP11 |
#undef OP12 |
#undef OP13 |
#ifdef OP14 |
#undef OP14 |
#endif |
#ifdef OP15 |
#undef OP15 |
#endif |
#undef OP00_LBL |
#undef OP01_LBL |
#undef OP12_TEX |
#undef OP14_TEX |
#undef OP12_SAMPLE |
#undef OP13_SAMPLE |
#undef OP14_SAMPLE |
#undef OP15_SAMPLE |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_parse.c |
---|
0,0 → 1,307 |
/************************************************************************** |
* |
* Copyright 2007 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 "util/u_debug.h" |
#include "pipe/p_shader_tokens.h" |
#include "tgsi_parse.h" |
#include "util/u_memory.h" |
unsigned |
tgsi_parse_init( |
struct tgsi_parse_context *ctx, |
const struct tgsi_token *tokens ) |
{ |
ctx->FullHeader.Header = *(struct tgsi_header *) &tokens[0]; |
if( ctx->FullHeader.Header.HeaderSize >= 2 ) { |
ctx->FullHeader.Processor = *(struct tgsi_processor *) &tokens[1]; |
} |
else { |
return TGSI_PARSE_ERROR; |
} |
ctx->Tokens = tokens; |
ctx->Position = ctx->FullHeader.Header.HeaderSize; |
return TGSI_PARSE_OK; |
} |
void |
tgsi_parse_free( |
struct tgsi_parse_context *ctx ) |
{ |
} |
boolean |
tgsi_parse_end_of_tokens( |
struct tgsi_parse_context *ctx ) |
{ |
return ctx->Position >= |
ctx->FullHeader.Header.HeaderSize + ctx->FullHeader.Header.BodySize; |
} |
/** |
* This function is used to avoid and work-around type punning/aliasing |
* warnings. The warnings seem harmless on x86 but on PPC they cause |
* real failures. |
*/ |
static INLINE void |
copy_token(void *dst, const void *src) |
{ |
memcpy(dst, src, 4); |
} |
/** |
* Get next 4-byte token, return it at address specified by 'token' |
*/ |
static void |
next_token( |
struct tgsi_parse_context *ctx, |
void *token ) |
{ |
assert( !tgsi_parse_end_of_tokens( ctx ) ); |
copy_token(token, &ctx->Tokens[ctx->Position]); |
ctx->Position++; |
} |
void |
tgsi_parse_token( |
struct tgsi_parse_context *ctx ) |
{ |
struct tgsi_token token; |
unsigned i; |
next_token( ctx, &token ); |
switch( token.Type ) { |
case TGSI_TOKEN_TYPE_DECLARATION: |
{ |
struct tgsi_full_declaration *decl = &ctx->FullToken.FullDeclaration; |
memset(decl, 0, sizeof *decl); |
copy_token(&decl->Declaration, &token); |
next_token( ctx, &decl->Range ); |
if (decl->Declaration.Dimension) { |
next_token(ctx, &decl->Dim); |
} |
if( decl->Declaration.Interpolate ) { |
next_token( ctx, &decl->Interp ); |
} |
if( decl->Declaration.Semantic ) { |
next_token( ctx, &decl->Semantic ); |
} |
if (decl->Declaration.File == TGSI_FILE_RESOURCE) { |
next_token(ctx, &decl->Resource); |
} |
if (decl->Declaration.File == TGSI_FILE_SAMPLER_VIEW) { |
next_token(ctx, &decl->SamplerView); |
} |
if( decl->Declaration.Array ) { |
next_token(ctx, &decl->Array); |
} |
break; |
} |
case TGSI_TOKEN_TYPE_IMMEDIATE: |
{ |
struct tgsi_full_immediate *imm = &ctx->FullToken.FullImmediate; |
uint imm_count; |
memset(imm, 0, sizeof *imm); |
copy_token(&imm->Immediate, &token); |
imm_count = imm->Immediate.NrTokens - 1; |
switch (imm->Immediate.DataType) { |
case TGSI_IMM_FLOAT32: |
for (i = 0; i < imm_count; i++) { |
next_token(ctx, &imm->u[i].Float); |
} |
break; |
case TGSI_IMM_UINT32: |
for (i = 0; i < imm_count; i++) { |
next_token(ctx, &imm->u[i].Uint); |
} |
break; |
case TGSI_IMM_INT32: |
for (i = 0; i < imm_count; i++) { |
next_token(ctx, &imm->u[i].Int); |
} |
break; |
default: |
assert( 0 ); |
} |
break; |
} |
case TGSI_TOKEN_TYPE_INSTRUCTION: |
{ |
struct tgsi_full_instruction *inst = &ctx->FullToken.FullInstruction; |
memset(inst, 0, sizeof *inst); |
copy_token(&inst->Instruction, &token); |
if (inst->Instruction.Predicate) { |
next_token(ctx, &inst->Predicate); |
} |
if (inst->Instruction.Label) { |
next_token( ctx, &inst->Label); |
} |
if (inst->Instruction.Texture) { |
next_token( ctx, &inst->Texture); |
for( i = 0; i < inst->Texture.NumOffsets; i++ ) { |
next_token( ctx, &inst->TexOffsets[i] ); |
} |
} |
assert( inst->Instruction.NumDstRegs <= TGSI_FULL_MAX_DST_REGISTERS ); |
for( i = 0; i < inst->Instruction.NumDstRegs; i++ ) { |
next_token( ctx, &inst->Dst[i].Register ); |
if( inst->Dst[i].Register.Indirect ) |
next_token( ctx, &inst->Dst[i].Indirect ); |
if( inst->Dst[i].Register.Dimension ) { |
next_token( ctx, &inst->Dst[i].Dimension ); |
/* |
* No support for multi-dimensional addressing. |
*/ |
assert( !inst->Dst[i].Dimension.Dimension ); |
if( inst->Dst[i].Dimension.Indirect ) |
next_token( ctx, &inst->Dst[i].DimIndirect ); |
} |
} |
assert( inst->Instruction.NumSrcRegs <= TGSI_FULL_MAX_SRC_REGISTERS ); |
for( i = 0; i < inst->Instruction.NumSrcRegs; i++ ) { |
next_token( ctx, &inst->Src[i].Register ); |
if( inst->Src[i].Register.Indirect ) |
next_token( ctx, &inst->Src[i].Indirect ); |
if( inst->Src[i].Register.Dimension ) { |
next_token( ctx, &inst->Src[i].Dimension ); |
/* |
* No support for multi-dimensional addressing. |
*/ |
assert( !inst->Src[i].Dimension.Dimension ); |
if( inst->Src[i].Dimension.Indirect ) |
next_token( ctx, &inst->Src[i].DimIndirect ); |
} |
} |
break; |
} |
case TGSI_TOKEN_TYPE_PROPERTY: |
{ |
struct tgsi_full_property *prop = &ctx->FullToken.FullProperty; |
uint prop_count; |
memset(prop, 0, sizeof *prop); |
copy_token(&prop->Property, &token); |
prop_count = prop->Property.NrTokens - 1; |
for (i = 0; i < prop_count; i++) { |
next_token(ctx, &prop->u[i]); |
} |
break; |
} |
default: |
assert( 0 ); |
} |
} |
/** |
* Make a new copy of a token array. |
*/ |
struct tgsi_token * |
tgsi_dup_tokens(const struct tgsi_token *tokens) |
{ |
unsigned n = tgsi_num_tokens(tokens); |
unsigned bytes = n * sizeof(struct tgsi_token); |
struct tgsi_token *new_tokens = (struct tgsi_token *) MALLOC(bytes); |
if (new_tokens) |
memcpy(new_tokens, tokens, bytes); |
return new_tokens; |
} |
/** |
* Allocate memory for num_tokens tokens. |
*/ |
struct tgsi_token * |
tgsi_alloc_tokens(unsigned num_tokens) |
{ |
unsigned bytes = num_tokens * sizeof(struct tgsi_token); |
return (struct tgsi_token *) MALLOC(bytes); |
} |
void |
tgsi_dump_tokens(const struct tgsi_token *tokens) |
{ |
const unsigned *dwords = (const unsigned *)tokens; |
int nr = tgsi_num_tokens(tokens); |
int i; |
assert(sizeof(*tokens) == sizeof(unsigned)); |
debug_printf("const unsigned tokens[%d] = {\n", nr); |
for (i = 0; i < nr; i++) |
debug_printf("0x%08x,\n", dwords[i]); |
debug_printf("};\n"); |
} |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_parse.h |
---|
0,0 → 1,159 |
/************************************************************************** |
* |
* Copyright 2007 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. |
* |
**************************************************************************/ |
#ifndef TGSI_PARSE_H |
#define TGSI_PARSE_H |
#include "pipe/p_compiler.h" |
#include "pipe/p_shader_tokens.h" |
#if defined __cplusplus |
extern "C" { |
#endif |
struct tgsi_full_header |
{ |
struct tgsi_header Header; |
struct tgsi_processor Processor; |
}; |
struct tgsi_full_dst_register |
{ |
struct tgsi_dst_register Register; |
struct tgsi_ind_register Indirect; |
struct tgsi_dimension Dimension; |
struct tgsi_ind_register DimIndirect; |
}; |
struct tgsi_full_src_register |
{ |
struct tgsi_src_register Register; |
struct tgsi_ind_register Indirect; |
struct tgsi_dimension Dimension; |
struct tgsi_ind_register DimIndirect; |
}; |
struct tgsi_full_declaration |
{ |
struct tgsi_declaration Declaration; |
struct tgsi_declaration_range Range; |
struct tgsi_declaration_dimension Dim; |
struct tgsi_declaration_interp Interp; |
struct tgsi_declaration_semantic Semantic; |
struct tgsi_declaration_resource Resource; |
struct tgsi_declaration_sampler_view SamplerView; |
struct tgsi_declaration_array Array; |
}; |
struct tgsi_full_immediate |
{ |
struct tgsi_immediate Immediate; |
union tgsi_immediate_data u[4]; |
}; |
struct tgsi_full_property |
{ |
struct tgsi_property Property; |
struct tgsi_property_data u[8]; |
}; |
#define TGSI_FULL_MAX_DST_REGISTERS 2 |
#define TGSI_FULL_MAX_SRC_REGISTERS 5 /* SAMPLE_D has 5 */ |
#define TGSI_FULL_MAX_TEX_OFFSETS 4 |
struct tgsi_full_instruction |
{ |
struct tgsi_instruction Instruction; |
struct tgsi_instruction_predicate Predicate; |
struct tgsi_instruction_label Label; |
struct tgsi_instruction_texture Texture; |
struct tgsi_full_dst_register Dst[TGSI_FULL_MAX_DST_REGISTERS]; |
struct tgsi_full_src_register Src[TGSI_FULL_MAX_SRC_REGISTERS]; |
struct tgsi_texture_offset TexOffsets[TGSI_FULL_MAX_TEX_OFFSETS]; |
}; |
union tgsi_full_token |
{ |
struct tgsi_token Token; |
struct tgsi_full_declaration FullDeclaration; |
struct tgsi_full_immediate FullImmediate; |
struct tgsi_full_instruction FullInstruction; |
struct tgsi_full_property FullProperty; |
}; |
struct tgsi_parse_context |
{ |
const struct tgsi_token *Tokens; |
unsigned Position; |
struct tgsi_full_header FullHeader; |
union tgsi_full_token FullToken; |
}; |
#define TGSI_PARSE_OK 0 |
#define TGSI_PARSE_ERROR 1 |
unsigned |
tgsi_parse_init( |
struct tgsi_parse_context *ctx, |
const struct tgsi_token *tokens ); |
void |
tgsi_parse_free( |
struct tgsi_parse_context *ctx ); |
boolean |
tgsi_parse_end_of_tokens( |
struct tgsi_parse_context *ctx ); |
void |
tgsi_parse_token( |
struct tgsi_parse_context *ctx ); |
static INLINE unsigned |
tgsi_num_tokens(const struct tgsi_token *tokens) |
{ |
struct tgsi_header header; |
memcpy(&header, tokens, sizeof(header)); |
return header.HeaderSize + header.BodySize; |
} |
void |
tgsi_dump_tokens(const struct tgsi_token *tokens); |
struct tgsi_token * |
tgsi_dup_tokens(const struct tgsi_token *tokens); |
struct tgsi_token * |
tgsi_alloc_tokens(unsigned num_tokens); |
#if defined __cplusplus |
} |
#endif |
#endif /* TGSI_PARSE_H */ |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_sanity.c |
---|
0,0 → 1,562 |
/************************************************************************** |
* |
* Copyright 2008 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 "util/u_debug.h" |
#include "util/u_memory.h" |
#include "util/u_prim.h" |
#include "cso_cache/cso_hash.h" |
#include "tgsi_sanity.h" |
#include "tgsi_info.h" |
#include "tgsi_iterate.h" |
DEBUG_GET_ONCE_BOOL_OPTION(print_sanity, "TGSI_PRINT_SANITY", FALSE) |
typedef struct { |
uint file : 28; |
/* max 2 dimensions */ |
uint dimensions : 4; |
uint indices[2]; |
} scan_register; |
struct sanity_check_ctx |
{ |
struct tgsi_iterate_context iter; |
struct cso_hash *regs_decl; |
struct cso_hash *regs_used; |
struct cso_hash *regs_ind_used; |
uint num_imms; |
uint num_instructions; |
uint index_of_END; |
uint errors; |
uint warnings; |
uint implied_array_size; |
boolean print; |
}; |
static INLINE unsigned |
scan_register_key(const scan_register *reg) |
{ |
unsigned key = reg->file; |
key |= (reg->indices[0] << 4); |
key |= (reg->indices[1] << 18); |
return key; |
} |
static void |
fill_scan_register1d(scan_register *reg, |
uint file, uint index) |
{ |
reg->file = file; |
reg->dimensions = 1; |
reg->indices[0] = index; |
reg->indices[1] = 0; |
} |
static void |
fill_scan_register2d(scan_register *reg, |
uint file, uint index1, uint index2) |
{ |
reg->file = file; |
reg->dimensions = 2; |
reg->indices[0] = index1; |
reg->indices[1] = index2; |
} |
static void |
scan_register_dst(scan_register *reg, |
struct tgsi_full_dst_register *dst) |
{ |
if (dst->Register.Dimension) { |
/*FIXME: right now we don't support indirect |
* multidimensional addressing */ |
fill_scan_register2d(reg, |
dst->Register.File, |
dst->Register.Index, |
dst->Dimension.Index); |
} else { |
fill_scan_register1d(reg, |
dst->Register.File, |
dst->Register.Index); |
} |
} |
static void |
scan_register_src(scan_register *reg, |
struct tgsi_full_src_register *src) |
{ |
if (src->Register.Dimension) { |
/*FIXME: right now we don't support indirect |
* multidimensional addressing */ |
fill_scan_register2d(reg, |
src->Register.File, |
src->Register.Index, |
src->Dimension.Index); |
} else { |
fill_scan_register1d(reg, |
src->Register.File, |
src->Register.Index); |
} |
} |
static scan_register * |
create_scan_register_src(struct tgsi_full_src_register *src) |
{ |
scan_register *reg = MALLOC(sizeof(scan_register)); |
scan_register_src(reg, src); |
return reg; |
} |
static scan_register * |
create_scan_register_dst(struct tgsi_full_dst_register *dst) |
{ |
scan_register *reg = MALLOC(sizeof(scan_register)); |
scan_register_dst(reg, dst); |
return reg; |
} |
static void |
report_error( |
struct sanity_check_ctx *ctx, |
const char *format, |
... ) |
{ |
va_list args; |
if (!ctx->print) |
return; |
debug_printf( "Error : " ); |
va_start( args, format ); |
_debug_vprintf( format, args ); |
va_end( args ); |
debug_printf( "\n" ); |
ctx->errors++; |
} |
static void |
report_warning( |
struct sanity_check_ctx *ctx, |
const char *format, |
... ) |
{ |
va_list args; |
if (!ctx->print) |
return; |
debug_printf( "Warning: " ); |
va_start( args, format ); |
_debug_vprintf( format, args ); |
va_end( args ); |
debug_printf( "\n" ); |
ctx->warnings++; |
} |
static boolean |
check_file_name( |
struct sanity_check_ctx *ctx, |
uint file ) |
{ |
if (file <= TGSI_FILE_NULL || file >= TGSI_FILE_COUNT) { |
report_error( ctx, "(%u): Invalid register file name", file ); |
return FALSE; |
} |
return TRUE; |
} |
static boolean |
is_register_declared( |
struct sanity_check_ctx *ctx, |
const scan_register *reg) |
{ |
void *data = cso_hash_find_data_from_template( |
ctx->regs_decl, scan_register_key(reg), |
(void*)reg, sizeof(scan_register)); |
return data ? TRUE : FALSE; |
} |
static boolean |
is_any_register_declared( |
struct sanity_check_ctx *ctx, |
uint file ) |
{ |
struct cso_hash_iter iter = |
cso_hash_first_node(ctx->regs_decl); |
while (!cso_hash_iter_is_null(iter)) { |
scan_register *reg = (scan_register *)cso_hash_iter_data(iter); |
if (reg->file == file) |
return TRUE; |
iter = cso_hash_iter_next(iter); |
} |
return FALSE; |
} |
static boolean |
is_register_used( |
struct sanity_check_ctx *ctx, |
scan_register *reg) |
{ |
void *data = cso_hash_find_data_from_template( |
ctx->regs_used, scan_register_key(reg), |
reg, sizeof(scan_register)); |
return data ? TRUE : FALSE; |
} |
static boolean |
is_ind_register_used( |
struct sanity_check_ctx *ctx, |
scan_register *reg) |
{ |
return cso_hash_contains(ctx->regs_ind_used, reg->file); |
} |
static const char *file_names[TGSI_FILE_COUNT] = |
{ |
"NULL", |
"CONST", |
"IN", |
"OUT", |
"TEMP", |
"SAMP", |
"ADDR", |
"IMM", |
"PRED", |
"SV", |
"RES" |
}; |
static boolean |
check_register_usage( |
struct sanity_check_ctx *ctx, |
scan_register *reg, |
const char *name, |
boolean indirect_access ) |
{ |
if (!check_file_name( ctx, reg->file )) { |
FREE(reg); |
return FALSE; |
} |
if (indirect_access) { |
/* Note that 'index' is an offset relative to the value of the |
* address register. No range checking done here.*/ |
reg->indices[0] = 0; |
reg->indices[1] = 0; |
if (!is_any_register_declared( ctx, reg->file )) |
report_error( ctx, "%s: Undeclared %s register", file_names[reg->file], name ); |
if (!is_ind_register_used(ctx, reg)) |
cso_hash_insert(ctx->regs_ind_used, reg->file, reg); |
else |
FREE(reg); |
} |
else { |
if (!is_register_declared( ctx, reg )) { |
if (reg->dimensions == 2) { |
report_error( ctx, "%s[%d][%d]: Undeclared %s register", file_names[reg->file], |
reg->indices[0], reg->indices[1], name ); |
} |
else { |
report_error( ctx, "%s[%d]: Undeclared %s register", file_names[reg->file], |
reg->indices[0], name ); |
} |
} |
if (!is_register_used( ctx, reg )) |
cso_hash_insert(ctx->regs_used, scan_register_key(reg), reg); |
else |
FREE(reg); |
} |
return TRUE; |
} |
static boolean |
iter_instruction( |
struct tgsi_iterate_context *iter, |
struct tgsi_full_instruction *inst ) |
{ |
struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; |
const struct tgsi_opcode_info *info; |
uint i; |
if (inst->Instruction.Opcode == TGSI_OPCODE_END) { |
if (ctx->index_of_END != ~0) { |
report_error( ctx, "Too many END instructions" ); |
} |
ctx->index_of_END = ctx->num_instructions; |
} |
info = tgsi_get_opcode_info( inst->Instruction.Opcode ); |
if (info == NULL) { |
report_error( ctx, "(%u): Invalid instruction opcode", inst->Instruction.Opcode ); |
return TRUE; |
} |
if (info->num_dst != inst->Instruction.NumDstRegs) { |
report_error( ctx, "%s: Invalid number of destination operands, should be %u", info->mnemonic, info->num_dst ); |
} |
if (info->num_src != inst->Instruction.NumSrcRegs) { |
report_error( ctx, "%s: Invalid number of source operands, should be %u", info->mnemonic, info->num_src ); |
} |
/* Check destination and source registers' validity. |
* Mark the registers as used. |
*/ |
for (i = 0; i < inst->Instruction.NumDstRegs; i++) { |
scan_register *reg = create_scan_register_dst(&inst->Dst[i]); |
check_register_usage( |
ctx, |
reg, |
"destination", |
FALSE ); |
if (!inst->Dst[i].Register.WriteMask) { |
report_error(ctx, "Destination register has empty writemask"); |
} |
} |
for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { |
scan_register *reg = create_scan_register_src(&inst->Src[i]); |
check_register_usage( |
ctx, |
reg, |
"source", |
(boolean)inst->Src[i].Register.Indirect ); |
if (inst->Src[i].Register.Indirect) { |
scan_register *ind_reg = MALLOC(sizeof(scan_register)); |
fill_scan_register1d(ind_reg, |
inst->Src[i].Indirect.File, |
inst->Src[i].Indirect.Index); |
check_register_usage( |
ctx, |
ind_reg, |
"indirect", |
FALSE ); |
} |
} |
ctx->num_instructions++; |
return TRUE; |
} |
static void |
check_and_declare(struct sanity_check_ctx *ctx, |
scan_register *reg) |
{ |
if (is_register_declared( ctx, reg)) |
report_error( ctx, "%s[%u]: The same register declared more than once", |
file_names[reg->file], reg->indices[0] ); |
cso_hash_insert(ctx->regs_decl, |
scan_register_key(reg), |
reg); |
} |
static boolean |
iter_declaration( |
struct tgsi_iterate_context *iter, |
struct tgsi_full_declaration *decl ) |
{ |
struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; |
uint file; |
uint i; |
/* No declarations allowed after the first instruction. |
*/ |
if (ctx->num_instructions > 0) |
report_error( ctx, "Instruction expected but declaration found" ); |
/* Check registers' validity. |
* Mark the registers as declared. |
*/ |
file = decl->Declaration.File; |
if (!check_file_name( ctx, file )) |
return TRUE; |
for (i = decl->Range.First; i <= decl->Range.Last; i++) { |
/* declared TGSI_FILE_INPUT's for geometry processor |
* have an implied second dimension */ |
if (file == TGSI_FILE_INPUT && |
ctx->iter.processor.Processor == TGSI_PROCESSOR_GEOMETRY) { |
uint vert; |
for (vert = 0; vert < ctx->implied_array_size; ++vert) { |
scan_register *reg = MALLOC(sizeof(scan_register)); |
fill_scan_register2d(reg, file, i, vert); |
check_and_declare(ctx, reg); |
} |
} else { |
scan_register *reg = MALLOC(sizeof(scan_register)); |
if (decl->Declaration.Dimension) { |
fill_scan_register2d(reg, file, i, decl->Dim.Index2D); |
} else { |
fill_scan_register1d(reg, file, i); |
} |
check_and_declare(ctx, reg); |
} |
} |
return TRUE; |
} |
static boolean |
iter_immediate( |
struct tgsi_iterate_context *iter, |
struct tgsi_full_immediate *imm ) |
{ |
struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; |
scan_register *reg; |
/* No immediates allowed after the first instruction. |
*/ |
if (ctx->num_instructions > 0) |
report_error( ctx, "Instruction expected but immediate found" ); |
/* Mark the register as declared. |
*/ |
reg = MALLOC(sizeof(scan_register)); |
fill_scan_register1d(reg, TGSI_FILE_IMMEDIATE, ctx->num_imms); |
cso_hash_insert(ctx->regs_decl, scan_register_key(reg), reg); |
ctx->num_imms++; |
/* Check data type validity. |
*/ |
if (imm->Immediate.DataType != TGSI_IMM_FLOAT32 && |
imm->Immediate.DataType != TGSI_IMM_UINT32 && |
imm->Immediate.DataType != TGSI_IMM_INT32) { |
report_error( ctx, "(%u): Invalid immediate data type", imm->Immediate.DataType ); |
return TRUE; |
} |
return TRUE; |
} |
static boolean |
iter_property( |
struct tgsi_iterate_context *iter, |
struct tgsi_full_property *prop ) |
{ |
struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; |
if (iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY && |
prop->Property.PropertyName == TGSI_PROPERTY_GS_INPUT_PRIM) { |
ctx->implied_array_size = u_vertices_per_prim(prop->u[0].Data); |
} |
return TRUE; |
} |
static boolean |
epilog( |
struct tgsi_iterate_context *iter ) |
{ |
struct sanity_check_ctx *ctx = (struct sanity_check_ctx *) iter; |
/* There must be an END instruction somewhere. |
*/ |
if (ctx->index_of_END == ~0) { |
report_error( ctx, "Missing END instruction" ); |
} |
/* Check if all declared registers were used. |
*/ |
{ |
struct cso_hash_iter iter = |
cso_hash_first_node(ctx->regs_decl); |
while (!cso_hash_iter_is_null(iter)) { |
scan_register *reg = (scan_register *)cso_hash_iter_data(iter); |
if (!is_register_used(ctx, reg) && !is_ind_register_used(ctx, reg)) { |
report_warning( ctx, "%s[%u]: Register never used", |
file_names[reg->file], reg->indices[0] ); |
} |
iter = cso_hash_iter_next(iter); |
} |
} |
/* Print totals, if any. |
*/ |
if (ctx->errors || ctx->warnings) |
debug_printf( "%u errors, %u warnings\n", ctx->errors, ctx->warnings ); |
return TRUE; |
} |
static void |
regs_hash_destroy(struct cso_hash *hash) |
{ |
struct cso_hash_iter iter = cso_hash_first_node(hash); |
while (!cso_hash_iter_is_null(iter)) { |
scan_register *reg = (scan_register *)cso_hash_iter_data(iter); |
iter = cso_hash_erase(hash, iter); |
assert(reg->file < TGSI_FILE_COUNT); |
FREE(reg); |
} |
cso_hash_delete(hash); |
} |
boolean |
tgsi_sanity_check( |
const struct tgsi_token *tokens ) |
{ |
struct sanity_check_ctx ctx; |
ctx.iter.prolog = NULL; |
ctx.iter.iterate_instruction = iter_instruction; |
ctx.iter.iterate_declaration = iter_declaration; |
ctx.iter.iterate_immediate = iter_immediate; |
ctx.iter.iterate_property = iter_property; |
ctx.iter.epilog = epilog; |
ctx.regs_decl = cso_hash_create(); |
ctx.regs_used = cso_hash_create(); |
ctx.regs_ind_used = cso_hash_create(); |
ctx.num_imms = 0; |
ctx.num_instructions = 0; |
ctx.index_of_END = ~0; |
ctx.errors = 0; |
ctx.warnings = 0; |
ctx.implied_array_size = 0; |
ctx.print = debug_get_option_print_sanity(); |
if (!tgsi_iterate_shader( tokens, &ctx.iter )) |
return FALSE; |
regs_hash_destroy(ctx.regs_decl); |
regs_hash_destroy(ctx.regs_used); |
regs_hash_destroy(ctx.regs_ind_used); |
return ctx.errors == 0; |
} |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_sanity.h |
---|
0,0 → 1,52 |
/************************************************************************** |
* |
* Copyright 2008 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. |
* |
**************************************************************************/ |
#ifndef TGSI_SANITY_H |
#define TGSI_SANITY_H |
#if defined __cplusplus |
extern "C" { |
#endif |
#include "pipe/p_compiler.h" |
struct tgsi_token; |
/* Check the given token stream for errors and common mistakes. |
* Diagnostic messages are printed out to the debug output, and is |
* controlled by the debug option TGSI_PRINT_SANITY (default false). |
* Returns TRUE if there are no errors, even though there could be some warnings. |
*/ |
boolean |
tgsi_sanity_check( |
const struct tgsi_token *tokens ); |
#if defined __cplusplus |
} |
#endif |
#endif /* TGSI_SANITY_H */ |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_scan.c |
---|
0,0 → 1,380 |
/************************************************************************** |
* |
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. |
* All Rights Reserved. |
* Copyright 2008 VMware, Inc. 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. |
* |
**************************************************************************/ |
/** |
* TGSI program scan utility. |
* Used to determine which registers and instructions are used by a shader. |
* |
* Authors: Brian Paul |
*/ |
#include "util/u_debug.h" |
#include "util/u_math.h" |
#include "util/u_prim.h" |
#include "tgsi/tgsi_parse.h" |
#include "tgsi/tgsi_util.h" |
#include "tgsi/tgsi_scan.h" |
/** |
* Scan the given TGSI shader to collect information such as number of |
* registers used, special instructions used, etc. |
* \return info the result of the scan |
*/ |
void |
tgsi_scan_shader(const struct tgsi_token *tokens, |
struct tgsi_shader_info *info) |
{ |
uint procType, i; |
struct tgsi_parse_context parse; |
memset(info, 0, sizeof(*info)); |
for (i = 0; i < TGSI_FILE_COUNT; i++) |
info->file_max[i] = -1; |
/** |
** Setup to begin parsing input shader |
**/ |
if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) { |
debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n"); |
return; |
} |
procType = parse.FullHeader.Processor.Processor; |
assert(procType == TGSI_PROCESSOR_FRAGMENT || |
procType == TGSI_PROCESSOR_VERTEX || |
procType == TGSI_PROCESSOR_GEOMETRY || |
procType == TGSI_PROCESSOR_COMPUTE); |
info->processor = procType; |
/** |
** Loop over incoming program tokens/instructions |
*/ |
while( !tgsi_parse_end_of_tokens( &parse ) ) { |
info->num_tokens++; |
tgsi_parse_token( &parse ); |
switch( parse.FullToken.Token.Type ) { |
case TGSI_TOKEN_TYPE_INSTRUCTION: |
{ |
const struct tgsi_full_instruction *fullinst |
= &parse.FullToken.FullInstruction; |
uint i; |
assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST); |
info->opcode_count[fullinst->Instruction.Opcode]++; |
for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) { |
const struct tgsi_full_src_register *src = |
&fullinst->Src[i]; |
int ind = src->Register.Index; |
/* Mark which inputs are effectively used */ |
if (src->Register.File == TGSI_FILE_INPUT) { |
unsigned usage_mask; |
usage_mask = tgsi_util_get_inst_usage_mask(fullinst, i); |
if (src->Register.Indirect) { |
for (ind = 0; ind < info->num_inputs; ++ind) { |
info->input_usage_mask[ind] |= usage_mask; |
} |
} else { |
assert(ind >= 0); |
assert(ind < PIPE_MAX_SHADER_INPUTS); |
info->input_usage_mask[ind] |= usage_mask; |
} |
if (procType == TGSI_PROCESSOR_FRAGMENT && |
src->Register.File == TGSI_FILE_INPUT && |
info->reads_position && |
src->Register.Index == 0 && |
(src->Register.SwizzleX == TGSI_SWIZZLE_Z || |
src->Register.SwizzleY == TGSI_SWIZZLE_Z || |
src->Register.SwizzleZ == TGSI_SWIZZLE_Z || |
src->Register.SwizzleW == TGSI_SWIZZLE_Z)) { |
info->reads_z = TRUE; |
} |
} |
/* check for indirect register reads */ |
if (src->Register.Indirect) { |
info->indirect_files |= (1 << src->Register.File); |
} |
} |
/* check for indirect register writes */ |
for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) { |
const struct tgsi_full_dst_register *dst = &fullinst->Dst[i]; |
if (dst->Register.Indirect) { |
info->indirect_files |= (1 << dst->Register.File); |
} |
} |
info->num_instructions++; |
} |
break; |
case TGSI_TOKEN_TYPE_DECLARATION: |
{ |
const struct tgsi_full_declaration *fulldecl |
= &parse.FullToken.FullDeclaration; |
const uint file = fulldecl->Declaration.File; |
uint reg; |
for (reg = fulldecl->Range.First; |
reg <= fulldecl->Range.Last; |
reg++) { |
/* only first 32 regs will appear in this bitfield */ |
info->file_mask[file] |= (1 << reg); |
info->file_count[file]++; |
info->file_max[file] = MAX2(info->file_max[file], (int)reg); |
if (file == TGSI_FILE_INPUT) { |
info->input_semantic_name[reg] = (ubyte)fulldecl->Semantic.Name; |
info->input_semantic_index[reg] = (ubyte)fulldecl->Semantic.Index; |
info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate; |
info->input_centroid[reg] = (ubyte)fulldecl->Interp.Centroid; |
info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap; |
info->num_inputs++; |
if (procType == TGSI_PROCESSOR_FRAGMENT && |
fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION) |
info->reads_position = TRUE; |
} |
else if (file == TGSI_FILE_SYSTEM_VALUE) { |
unsigned index = fulldecl->Range.First; |
unsigned semName = fulldecl->Semantic.Name; |
info->system_value_semantic_name[index] = semName; |
info->num_system_values = MAX2(info->num_system_values, |
index + 1); |
/* |
info->system_value_semantic_name[info->num_system_values++] = |
fulldecl->Semantic.Name; |
*/ |
if (fulldecl->Semantic.Name == TGSI_SEMANTIC_INSTANCEID) { |
info->uses_instanceid = TRUE; |
} |
else if (fulldecl->Semantic.Name == TGSI_SEMANTIC_VERTEXID) { |
info->uses_vertexid = TRUE; |
} else if (fulldecl->Semantic.Name == TGSI_SEMANTIC_PRIMID) { |
info->uses_primid = TRUE; |
} |
} |
else if (file == TGSI_FILE_OUTPUT) { |
info->output_semantic_name[reg] = (ubyte)fulldecl->Semantic.Name; |
info->output_semantic_index[reg] = (ubyte)fulldecl->Semantic.Index; |
info->num_outputs++; |
if ((procType == TGSI_PROCESSOR_VERTEX || procType == TGSI_PROCESSOR_GEOMETRY) && |
fulldecl->Semantic.Name == TGSI_SEMANTIC_CLIPDIST) { |
info->num_written_clipdistance += util_bitcount(fulldecl->Declaration.UsageMask); |
} |
if ((procType == TGSI_PROCESSOR_VERTEX || procType == TGSI_PROCESSOR_GEOMETRY) && |
fulldecl->Semantic.Name == TGSI_SEMANTIC_CULLDIST) { |
info->num_written_culldistance += util_bitcount(fulldecl->Declaration.UsageMask); |
} |
/* extra info for special outputs */ |
if (procType == TGSI_PROCESSOR_FRAGMENT && |
fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION) |
info->writes_z = TRUE; |
if (procType == TGSI_PROCESSOR_FRAGMENT && |
fulldecl->Semantic.Name == TGSI_SEMANTIC_STENCIL) |
info->writes_stencil = TRUE; |
if (procType == TGSI_PROCESSOR_VERTEX && |
fulldecl->Semantic.Name == TGSI_SEMANTIC_EDGEFLAG) { |
info->writes_edgeflag = TRUE; |
} |
if (procType == TGSI_PROCESSOR_GEOMETRY && |
fulldecl->Semantic.Name == |
TGSI_SEMANTIC_VIEWPORT_INDEX) { |
info->writes_viewport_index = TRUE; |
} |
if (procType == TGSI_PROCESSOR_GEOMETRY && |
fulldecl->Semantic.Name == |
TGSI_SEMANTIC_LAYER) { |
info->writes_layer = TRUE; |
} |
} |
} |
} |
break; |
case TGSI_TOKEN_TYPE_IMMEDIATE: |
{ |
uint reg = info->immediate_count++; |
uint file = TGSI_FILE_IMMEDIATE; |
info->file_mask[file] |= (1 << reg); |
info->file_count[file]++; |
info->file_max[file] = MAX2(info->file_max[file], (int)reg); |
} |
break; |
case TGSI_TOKEN_TYPE_PROPERTY: |
{ |
const struct tgsi_full_property *fullprop |
= &parse.FullToken.FullProperty; |
info->properties[info->num_properties].name = |
fullprop->Property.PropertyName; |
memcpy(info->properties[info->num_properties].data, |
fullprop->u, 8 * sizeof(unsigned));; |
++info->num_properties; |
} |
break; |
default: |
assert( 0 ); |
} |
} |
info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] || |
info->opcode_count[TGSI_OPCODE_KILL]); |
/* extract simple properties */ |
for (i = 0; i < info->num_properties; ++i) { |
switch (info->properties[i].name) { |
case TGSI_PROPERTY_FS_COORD_ORIGIN: |
info->origin_lower_left = info->properties[i].data[0]; |
break; |
case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: |
info->pixel_center_integer = info->properties[i].data[0]; |
break; |
case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS: |
info->color0_writes_all_cbufs = info->properties[i].data[0]; |
break; |
case TGSI_PROPERTY_GS_INPUT_PRIM: |
/* The dimensions of the IN decleration in geometry shader have |
* to be deduced from the type of the input primitive. |
*/ |
if (procType == TGSI_PROCESSOR_GEOMETRY) { |
unsigned input_primitive = info->properties[i].data[0]; |
int num_verts = u_vertices_per_prim(input_primitive); |
int j; |
info->file_count[TGSI_FILE_INPUT] = num_verts; |
info->file_max[TGSI_FILE_INPUT] = |
MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1); |
for (j = 0; j < num_verts; ++j) { |
info->file_mask[TGSI_FILE_INPUT] |= (1 << j); |
} |
} |
break; |
default: |
; |
} |
} |
tgsi_parse_free (&parse); |
} |
/** |
* Check if the given shader is a "passthrough" shader consisting of only |
* MOV instructions of the form: MOV OUT[n], IN[n] |
* |
*/ |
boolean |
tgsi_is_passthrough_shader(const struct tgsi_token *tokens) |
{ |
struct tgsi_parse_context parse; |
/** |
** Setup to begin parsing input shader |
**/ |
if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) { |
debug_printf("tgsi_parse_init() failed in tgsi_is_passthrough_shader()!\n"); |
return FALSE; |
} |
/** |
** Loop over incoming program tokens/instructions |
*/ |
while (!tgsi_parse_end_of_tokens(&parse)) { |
tgsi_parse_token(&parse); |
switch (parse.FullToken.Token.Type) { |
case TGSI_TOKEN_TYPE_INSTRUCTION: |
{ |
struct tgsi_full_instruction *fullinst = |
&parse.FullToken.FullInstruction; |
const struct tgsi_full_src_register *src = |
&fullinst->Src[0]; |
const struct tgsi_full_dst_register *dst = |
&fullinst->Dst[0]; |
/* Do a whole bunch of checks for a simple move */ |
if (fullinst->Instruction.Opcode != TGSI_OPCODE_MOV || |
(src->Register.File != TGSI_FILE_INPUT && |
src->Register.File != TGSI_FILE_SYSTEM_VALUE) || |
dst->Register.File != TGSI_FILE_OUTPUT || |
src->Register.Index != dst->Register.Index || |
src->Register.Negate || |
src->Register.Absolute || |
src->Register.SwizzleX != TGSI_SWIZZLE_X || |
src->Register.SwizzleY != TGSI_SWIZZLE_Y || |
src->Register.SwizzleZ != TGSI_SWIZZLE_Z || |
src->Register.SwizzleW != TGSI_SWIZZLE_W || |
dst->Register.WriteMask != TGSI_WRITEMASK_XYZW) |
{ |
tgsi_parse_free(&parse); |
return FALSE; |
} |
} |
break; |
case TGSI_TOKEN_TYPE_DECLARATION: |
/* fall-through */ |
case TGSI_TOKEN_TYPE_IMMEDIATE: |
/* fall-through */ |
case TGSI_TOKEN_TYPE_PROPERTY: |
/* fall-through */ |
default: |
; /* no-op */ |
} |
} |
tgsi_parse_free(&parse); |
/* if we get here, it's a pass-through shader */ |
return TRUE; |
} |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_scan.h |
---|
0,0 → 1,107 |
/************************************************************************** |
* |
* Copyright 2008 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. |
* |
**************************************************************************/ |
#ifndef TGSI_SCAN_H |
#define TGSI_SCAN_H |
#include "pipe/p_compiler.h" |
#include "pipe/p_state.h" |
#include "pipe/p_shader_tokens.h" |
/** |
* Shader summary info |
*/ |
struct tgsi_shader_info |
{ |
uint num_tokens; |
ubyte num_inputs; |
ubyte num_outputs; |
ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; /**< TGSI_SEMANTIC_x */ |
ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS]; |
ubyte input_interpolate[PIPE_MAX_SHADER_INPUTS]; |
ubyte input_centroid[PIPE_MAX_SHADER_INPUTS]; |
ubyte input_usage_mask[PIPE_MAX_SHADER_INPUTS]; |
ubyte input_cylindrical_wrap[PIPE_MAX_SHADER_INPUTS]; |
ubyte output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; /**< TGSI_SEMANTIC_x */ |
ubyte output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; |
ubyte num_system_values; |
ubyte system_value_semantic_name[PIPE_MAX_SHADER_INPUTS]; |
ubyte processor; |
uint file_mask[TGSI_FILE_COUNT]; /**< bitmask of declared registers */ |
uint file_count[TGSI_FILE_COUNT]; /**< number of declared registers */ |
int file_max[TGSI_FILE_COUNT]; /**< highest index of declared registers */ |
uint immediate_count; /**< number of immediates declared */ |
uint num_instructions; |
uint opcode_count[TGSI_OPCODE_LAST]; /**< opcode histogram */ |
boolean reads_position; /**< does fragment shader read position? */ |
boolean reads_z; /**< does fragment shader read depth? */ |
boolean writes_z; /**< does fragment shader write Z value? */ |
boolean writes_stencil; /**< does fragment shader write stencil value? */ |
boolean writes_edgeflag; /**< vertex shader outputs edgeflag */ |
boolean uses_kill; /**< KILL or KILL_IF instruction used? */ |
boolean uses_instanceid; |
boolean uses_vertexid; |
boolean uses_primid; |
boolean origin_lower_left; |
boolean pixel_center_integer; |
boolean color0_writes_all_cbufs; |
boolean writes_viewport_index; |
boolean writes_layer; |
unsigned num_written_culldistance; |
unsigned num_written_clipdistance; |
/** |
* Bitmask indicating which register files are accessed with |
* indirect addressing. The bits are (1 << TGSI_FILE_x), etc. |
*/ |
unsigned indirect_files; |
struct { |
unsigned name; |
unsigned data[8]; |
} properties[TGSI_PROPERTY_COUNT]; |
uint num_properties; |
}; |
extern void |
tgsi_scan_shader(const struct tgsi_token *tokens, |
struct tgsi_shader_info *info); |
extern boolean |
tgsi_is_passthrough_shader(const struct tgsi_token *tokens); |
#endif /* TGSI_SCAN_H */ |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_strings.c |
---|
0,0 → 1,201 |
/************************************************************************** |
* |
* Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. |
* Copyright 2012 VMware, Inc. |
* 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 THE AUTHORS 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 "pipe/p_compiler.h" |
#include "util/u_memory.h" |
#include "tgsi_strings.h" |
const char *tgsi_processor_type_names[4] = |
{ |
"FRAG", |
"VERT", |
"GEOM", |
"COMP" |
}; |
static const char *tgsi_file_names[] = |
{ |
"NULL", |
"CONST", |
"IN", |
"OUT", |
"TEMP", |
"SAMP", |
"ADDR", |
"IMM", |
"PRED", |
"SV", |
"RES", |
"SVIEW" |
}; |
const char *tgsi_semantic_names[TGSI_SEMANTIC_COUNT] = |
{ |
"POSITION", |
"COLOR", |
"BCOLOR", |
"FOG", |
"PSIZE", |
"GENERIC", |
"NORMAL", |
"FACE", |
"EDGEFLAG", |
"PRIM_ID", |
"INSTANCEID", |
"VERTEXID", |
"STENCIL", |
"CLIPDIST", |
"CLIPVERTEX", |
"GRID_SIZE", |
"BLOCK_ID", |
"BLOCK_SIZE", |
"THREAD_ID", |
"TEXCOORD", |
"PCOORD", |
"VIEWPORT_INDEX", |
"LAYER", |
"CULLDIST" |
}; |
const char *tgsi_texture_names[TGSI_TEXTURE_COUNT] = |
{ |
"BUFFER", |
"1D", |
"2D", |
"3D", |
"CUBE", |
"RECT", |
"SHADOW1D", |
"SHADOW2D", |
"SHADOWRECT", |
"1D_ARRAY", |
"2D_ARRAY", |
"SHADOW1D_ARRAY", |
"SHADOW2D_ARRAY", |
"SHADOWCUBE", |
"2D_MSAA", |
"2D_ARRAY_MSAA", |
"CUBEARRAY", |
"SHADOWCUBEARRAY", |
"UNKNOWN", |
}; |
const char *tgsi_property_names[TGSI_PROPERTY_COUNT] = |
{ |
"GS_INPUT_PRIMITIVE", |
"GS_OUTPUT_PRIMITIVE", |
"GS_MAX_OUTPUT_VERTICES", |
"FS_COORD_ORIGIN", |
"FS_COORD_PIXEL_CENTER", |
"FS_COLOR0_WRITES_ALL_CBUFS", |
"FS_DEPTH_LAYOUT", |
"VS_PROHIBIT_UCPS" |
}; |
const char *tgsi_type_names[5] = |
{ |
"UNORM", |
"SNORM", |
"SINT", |
"UINT", |
"FLOAT" |
}; |
const char *tgsi_interpolate_names[TGSI_INTERPOLATE_COUNT] = |
{ |
"CONSTANT", |
"LINEAR", |
"PERSPECTIVE", |
"COLOR" |
}; |
const char *tgsi_primitive_names[PIPE_PRIM_MAX] = |
{ |
"POINTS", |
"LINES", |
"LINE_LOOP", |
"LINE_STRIP", |
"TRIANGLES", |
"TRIANGLE_STRIP", |
"TRIANGLE_FAN", |
"QUADS", |
"QUAD_STRIP", |
"POLYGON", |
"LINES_ADJACENCY", |
"LINE_STRIP_ADJACENCY", |
"TRIANGLES_ADJACENCY", |
"TRIANGLE_STRIP_ADJACENCY" |
}; |
const char *tgsi_fs_coord_origin_names[2] = |
{ |
"UPPER_LEFT", |
"LOWER_LEFT" |
}; |
const char *tgsi_fs_coord_pixel_center_names[2] = |
{ |
"HALF_INTEGER", |
"INTEGER" |
}; |
const char *tgsi_immediate_type_names[3] = |
{ |
"FLT32", |
"UINT32", |
"INT32" |
}; |
static INLINE void |
tgsi_strings_check(void) |
{ |
STATIC_ASSERT(Elements(tgsi_semantic_names) == TGSI_SEMANTIC_COUNT); |
STATIC_ASSERT(Elements(tgsi_texture_names) == TGSI_TEXTURE_COUNT); |
STATIC_ASSERT(Elements(tgsi_property_names) == TGSI_PROPERTY_COUNT); |
STATIC_ASSERT(Elements(tgsi_primitive_names) == PIPE_PRIM_MAX); |
STATIC_ASSERT(Elements(tgsi_interpolate_names) == TGSI_INTERPOLATE_COUNT); |
(void) tgsi_processor_type_names; |
(void) tgsi_type_names; |
(void) tgsi_immediate_type_names; |
(void) tgsi_fs_coord_origin_names; |
(void) tgsi_fs_coord_pixel_center_names; |
} |
const char * |
tgsi_file_name(unsigned file) |
{ |
STATIC_ASSERT(Elements(tgsi_file_names) == TGSI_FILE_COUNT); |
if (file < Elements(tgsi_file_names)) |
return tgsi_file_names[file]; |
else |
return "invalid file"; |
} |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_strings.h |
---|
0,0 → 1,71 |
/************************************************************************** |
* |
* Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. |
* Copyright 2012 VMware, Inc. |
* 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 THE AUTHORS 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. |
* |
**************************************************************************/ |
#ifndef TGSI_STRINGS_H |
#define TGSI_STRINGS_H |
#include "pipe/p_shader_tokens.h" |
#include "pipe/p_state.h" |
#if defined __cplusplus |
extern "C" { |
#endif |
extern const char *tgsi_processor_type_names[4]; |
extern const char *tgsi_semantic_names[TGSI_SEMANTIC_COUNT]; |
extern const char *tgsi_texture_names[TGSI_TEXTURE_COUNT]; |
extern const char *tgsi_property_names[TGSI_PROPERTY_COUNT]; |
extern const char *tgsi_type_names[5]; |
extern const char *tgsi_interpolate_names[TGSI_INTERPOLATE_COUNT]; |
extern const char *tgsi_primitive_names[PIPE_PRIM_MAX]; |
extern const char *tgsi_fs_coord_origin_names[2]; |
extern const char *tgsi_fs_coord_pixel_center_names[2]; |
extern const char *tgsi_immediate_type_names[3]; |
const char * |
tgsi_file_name(unsigned file); |
#if defined __cplusplus |
} |
#endif |
#endif /* TGSI_STRINGS_H */ |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_text.c |
---|
0,0 → 1,1591 |
/************************************************************************** |
* |
* Copyright 2008 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 "util/u_debug.h" |
#include "util/u_memory.h" |
#include "util/u_prim.h" |
#include "pipe/p_defines.h" |
#include "util/u_inlines.h" |
#include "tgsi_text.h" |
#include "tgsi_build.h" |
#include "tgsi_info.h" |
#include "tgsi_parse.h" |
#include "tgsi_sanity.h" |
#include "tgsi_strings.h" |
#include "tgsi_util.h" |
#include "tgsi_dump.h" |
static boolean is_alpha_underscore( const char *cur ) |
{ |
return |
(*cur >= 'a' && *cur <= 'z') || |
(*cur >= 'A' && *cur <= 'Z') || |
*cur == '_'; |
} |
static boolean is_digit( const char *cur ) |
{ |
return *cur >= '0' && *cur <= '9'; |
} |
static boolean is_digit_alpha_underscore( const char *cur ) |
{ |
return is_digit( cur ) || is_alpha_underscore( cur ); |
} |
static char uprcase( char c ) |
{ |
if (c >= 'a' && c <= 'z') |
return c + 'A' - 'a'; |
return c; |
} |
/* |
* Ignore case of str1 and assume str1 is already uppercase. |
* Return TRUE iff str1 and str2 are equal. |
*/ |
static int |
streq_nocase_uprcase(const char *str1, |
const char *str2) |
{ |
while (*str1 && *str2) { |
if (*str1 != uprcase(*str2)) |
return FALSE; |
str1++; |
str2++; |
} |
return *str1 == 0 && *str2 == 0; |
} |
/* Return TRUE if both strings match. |
* The second string is terminated by zero. |
* The pointer to the first string is moved at end of the read word |
* on success. |
*/ |
static boolean str_match_no_case( const char **pcur, const char *str ) |
{ |
const char *cur = *pcur; |
while (*str != '\0' && *str == uprcase( *cur )) { |
str++; |
cur++; |
} |
if (*str == '\0') { |
*pcur = cur; |
return TRUE; |
} |
return FALSE; |
} |
/* Return TRUE if both strings match. |
* The first string is be terminated by a non-digit non-letter non-underscore |
* character, the second string is terminated by zero. |
* The pointer to the first string is moved at end of the read word |
* on success. |
*/ |
static boolean str_match_nocase_whole( const char **pcur, const char *str ) |
{ |
const char *cur = *pcur; |
if (str_match_no_case(&cur, str) && |
!is_digit_alpha_underscore(cur)) { |
*pcur = cur; |
return TRUE; |
} |
return FALSE; |
} |
/* Eat zero or more whitespaces. |
*/ |
static void eat_opt_white( const char **pcur ) |
{ |
while (**pcur == ' ' || **pcur == '\t' || **pcur == '\n') |
(*pcur)++; |
} |
/* Eat one or more whitespaces. |
* Return TRUE if at least one whitespace eaten. |
*/ |
static boolean eat_white( const char **pcur ) |
{ |
const char *cur = *pcur; |
eat_opt_white( pcur ); |
return *pcur > cur; |
} |
/* Parse unsigned integer. |
* No checks for overflow. |
*/ |
static boolean parse_uint( const char **pcur, uint *val ) |
{ |
const char *cur = *pcur; |
if (is_digit( cur )) { |
*val = *cur++ - '0'; |
while (is_digit( cur )) |
*val = *val * 10 + *cur++ - '0'; |
*pcur = cur; |
return TRUE; |
} |
return FALSE; |
} |
static boolean parse_int( const char **pcur, int *val ) |
{ |
const char *cur = *pcur; |
int sign = (*cur == '-' ? -1 : 1); |
if (*cur == '+' || *cur == '-') |
cur++; |
if (parse_uint(&cur, (uint *)val)) { |
*val *= sign; |
*pcur = cur; |
return TRUE; |
} |
return FALSE; |
} |
static boolean parse_identifier( const char **pcur, char *ret ) |
{ |
const char *cur = *pcur; |
int i = 0; |
if (is_alpha_underscore( cur )) { |
ret[i++] = *cur++; |
while (is_alpha_underscore( cur ) || is_digit( cur )) |
ret[i++] = *cur++; |
ret[i++] = '\0'; |
*pcur = cur; |
return TRUE; |
} |
return FALSE; |
} |
/* Parse floating point. |
*/ |
static boolean parse_float( const char **pcur, float *val ) |
{ |
const char *cur = *pcur; |
boolean integral_part = FALSE; |
boolean fractional_part = FALSE; |
*val = (float) atof( cur ); |
if (*cur == '-' || *cur == '+') |
cur++; |
if (is_digit( cur )) { |
cur++; |
integral_part = TRUE; |
while (is_digit( cur )) |
cur++; |
} |
if (*cur == '.') { |
cur++; |
if (is_digit( cur )) { |
cur++; |
fractional_part = TRUE; |
while (is_digit( cur )) |
cur++; |
} |
} |
if (!integral_part && !fractional_part) |
return FALSE; |
if (uprcase( *cur ) == 'E') { |
cur++; |
if (*cur == '-' || *cur == '+') |
cur++; |
if (is_digit( cur )) { |
cur++; |
while (is_digit( cur )) |
cur++; |
} |
else |
return FALSE; |
} |
*pcur = cur; |
return TRUE; |
} |
struct translate_ctx |
{ |
const char *text; |
const char *cur; |
struct tgsi_token *tokens; |
struct tgsi_token *tokens_cur; |
struct tgsi_token *tokens_end; |
struct tgsi_header *header; |
unsigned processor : 4; |
int implied_array_size : 5; |
unsigned num_immediates; |
}; |
static void report_error( struct translate_ctx *ctx, const char *msg ) |
{ |
int line = 1; |
int column = 1; |
const char *itr = ctx->text; |
while (itr != ctx->cur) { |
if (*itr == '\n') { |
column = 1; |
++line; |
} |
++column; |
++itr; |
} |
debug_printf( "\nTGSI asm error: %s [%d : %d] \n", msg, line, column ); |
} |
/* Parse shader header. |
* Return TRUE for one of the following headers. |
* FRAG |
* GEOM |
* VERT |
*/ |
static boolean parse_header( struct translate_ctx *ctx ) |
{ |
uint processor; |
if (str_match_nocase_whole( &ctx->cur, "FRAG" )) |
processor = TGSI_PROCESSOR_FRAGMENT; |
else if (str_match_nocase_whole( &ctx->cur, "VERT" )) |
processor = TGSI_PROCESSOR_VERTEX; |
else if (str_match_nocase_whole( &ctx->cur, "GEOM" )) |
processor = TGSI_PROCESSOR_GEOMETRY; |
else if (str_match_nocase_whole( &ctx->cur, "COMP" )) |
processor = TGSI_PROCESSOR_COMPUTE; |
else { |
report_error( ctx, "Unknown header" ); |
return FALSE; |
} |
if (ctx->tokens_cur >= ctx->tokens_end) |
return FALSE; |
ctx->header = (struct tgsi_header *) ctx->tokens_cur++; |
*ctx->header = tgsi_build_header(); |
if (ctx->tokens_cur >= ctx->tokens_end) |
return FALSE; |
*(struct tgsi_processor *) ctx->tokens_cur++ = tgsi_build_processor( processor, ctx->header ); |
ctx->processor = processor; |
return TRUE; |
} |
static boolean parse_label( struct translate_ctx *ctx, uint *val ) |
{ |
const char *cur = ctx->cur; |
if (parse_uint( &cur, val )) { |
eat_opt_white( &cur ); |
if (*cur == ':') { |
cur++; |
ctx->cur = cur; |
return TRUE; |
} |
} |
return FALSE; |
} |
static boolean |
parse_file( const char **pcur, uint *file ) |
{ |
uint i; |
for (i = 0; i < TGSI_FILE_COUNT; i++) { |
const char *cur = *pcur; |
if (str_match_nocase_whole( &cur, tgsi_file_name(i) )) { |
*pcur = cur; |
*file = i; |
return TRUE; |
} |
} |
return FALSE; |
} |
static boolean |
parse_opt_writemask( |
struct translate_ctx *ctx, |
uint *writemask ) |
{ |
const char *cur; |
cur = ctx->cur; |
eat_opt_white( &cur ); |
if (*cur == '.') { |
cur++; |
*writemask = TGSI_WRITEMASK_NONE; |
eat_opt_white( &cur ); |
if (uprcase( *cur ) == 'X') { |
cur++; |
*writemask |= TGSI_WRITEMASK_X; |
} |
if (uprcase( *cur ) == 'Y') { |
cur++; |
*writemask |= TGSI_WRITEMASK_Y; |
} |
if (uprcase( *cur ) == 'Z') { |
cur++; |
*writemask |= TGSI_WRITEMASK_Z; |
} |
if (uprcase( *cur ) == 'W') { |
cur++; |
*writemask |= TGSI_WRITEMASK_W; |
} |
if (*writemask == TGSI_WRITEMASK_NONE) { |
report_error( ctx, "Writemask expected" ); |
return FALSE; |
} |
ctx->cur = cur; |
} |
else { |
*writemask = TGSI_WRITEMASK_XYZW; |
} |
return TRUE; |
} |
/* <register_file_bracket> ::= <file> `[' |
*/ |
static boolean |
parse_register_file_bracket( |
struct translate_ctx *ctx, |
uint *file ) |
{ |
if (!parse_file( &ctx->cur, file )) { |
report_error( ctx, "Unknown register file" ); |
return FALSE; |
} |
eat_opt_white( &ctx->cur ); |
if (*ctx->cur != '[') { |
report_error( ctx, "Expected `['" ); |
return FALSE; |
} |
ctx->cur++; |
return TRUE; |
} |
/* <register_file_bracket_index> ::= <register_file_bracket> <uint> |
*/ |
static boolean |
parse_register_file_bracket_index( |
struct translate_ctx *ctx, |
uint *file, |
int *index ) |
{ |
uint uindex; |
if (!parse_register_file_bracket( ctx, file )) |
return FALSE; |
eat_opt_white( &ctx->cur ); |
if (!parse_uint( &ctx->cur, &uindex )) { |
report_error( ctx, "Expected literal unsigned integer" ); |
return FALSE; |
} |
*index = (int) uindex; |
return TRUE; |
} |
/* Parse simple 1d register operand. |
* <register_dst> ::= <register_file_bracket_index> `]' |
*/ |
static boolean |
parse_register_1d(struct translate_ctx *ctx, |
uint *file, |
int *index ) |
{ |
if (!parse_register_file_bracket_index( ctx, file, index )) |
return FALSE; |
eat_opt_white( &ctx->cur ); |
if (*ctx->cur != ']') { |
report_error( ctx, "Expected `]'" ); |
return FALSE; |
} |
ctx->cur++; |
return TRUE; |
} |
struct parsed_bracket { |
int index; |
uint ind_file; |
int ind_index; |
uint ind_comp; |
uint ind_array; |
}; |
static boolean |
parse_register_bracket( |
struct translate_ctx *ctx, |
struct parsed_bracket *brackets) |
{ |
const char *cur; |
uint uindex; |
memset(brackets, 0, sizeof(struct parsed_bracket)); |
eat_opt_white( &ctx->cur ); |
cur = ctx->cur; |
if (parse_file( &cur, &brackets->ind_file )) { |
if (!parse_register_1d( ctx, &brackets->ind_file, |
&brackets->ind_index )) |
return FALSE; |
eat_opt_white( &ctx->cur ); |
if (*ctx->cur == '.') { |
ctx->cur++; |
eat_opt_white(&ctx->cur); |
switch (uprcase(*ctx->cur)) { |
case 'X': |
brackets->ind_comp = TGSI_SWIZZLE_X; |
break; |
case 'Y': |
brackets->ind_comp = TGSI_SWIZZLE_Y; |
break; |
case 'Z': |
brackets->ind_comp = TGSI_SWIZZLE_Z; |
break; |
case 'W': |
brackets->ind_comp = TGSI_SWIZZLE_W; |
break; |
default: |
report_error(ctx, "Expected indirect register swizzle component `x', `y', `z' or `w'"); |
return FALSE; |
} |
ctx->cur++; |
eat_opt_white(&ctx->cur); |
} |
if (*ctx->cur == '+' || *ctx->cur == '-') |
parse_int( &ctx->cur, &brackets->index ); |
else |
brackets->index = 0; |
} |
else { |
if (!parse_uint( &ctx->cur, &uindex )) { |
report_error( ctx, "Expected literal unsigned integer" ); |
return FALSE; |
} |
brackets->index = (int) uindex; |
brackets->ind_file = TGSI_FILE_NULL; |
brackets->ind_index = 0; |
} |
eat_opt_white( &ctx->cur ); |
if (*ctx->cur != ']') { |
report_error( ctx, "Expected `]'" ); |
return FALSE; |
} |
ctx->cur++; |
if (*ctx->cur == '(') { |
ctx->cur++; |
eat_opt_white( &ctx->cur ); |
if (!parse_uint( &ctx->cur, &brackets->ind_array )) { |
report_error( ctx, "Expected literal unsigned integer" ); |
return FALSE; |
} |
eat_opt_white( &ctx->cur ); |
if (*ctx->cur != ')') { |
report_error( ctx, "Expected `)'" ); |
return FALSE; |
} |
ctx->cur++; |
} |
return TRUE; |
} |
static boolean |
parse_opt_register_src_bracket( |
struct translate_ctx *ctx, |
struct parsed_bracket *brackets, |
int *parsed_brackets) |
{ |
const char *cur = ctx->cur; |
*parsed_brackets = 0; |
eat_opt_white( &cur ); |
if (cur[0] == '[') { |
++cur; |
ctx->cur = cur; |
if (!parse_register_bracket(ctx, brackets)) |
return FALSE; |
*parsed_brackets = 1; |
} |
return TRUE; |
} |
/* Parse source register operand. |
* <register_src> ::= <register_file_bracket_index> `]' | |
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' | |
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' | |
* <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]' |
*/ |
static boolean |
parse_register_src( |
struct translate_ctx *ctx, |
uint *file, |
struct parsed_bracket *brackets) |
{ |
brackets->ind_comp = TGSI_SWIZZLE_X; |
if (!parse_register_file_bracket( ctx, file )) |
return FALSE; |
if (!parse_register_bracket( ctx, brackets )) |
return FALSE; |
return TRUE; |
} |
struct parsed_dcl_bracket { |
uint first; |
uint last; |
}; |
static boolean |
parse_register_dcl_bracket( |
struct translate_ctx *ctx, |
struct parsed_dcl_bracket *bracket) |
{ |
uint uindex; |
memset(bracket, 0, sizeof(struct parsed_dcl_bracket)); |
eat_opt_white( &ctx->cur ); |
if (!parse_uint( &ctx->cur, &uindex )) { |
/* it can be an empty bracket [] which means its range |
* is from 0 to some implied size */ |
if (ctx->cur[0] == ']' && ctx->implied_array_size != 0) { |
bracket->first = 0; |
bracket->last = ctx->implied_array_size - 1; |
goto cleanup; |
} |
report_error( ctx, "Expected literal unsigned integer" ); |
return FALSE; |
} |
bracket->first = uindex; |
eat_opt_white( &ctx->cur ); |
if (ctx->cur[0] == '.' && ctx->cur[1] == '.') { |
uint uindex; |
ctx->cur += 2; |
eat_opt_white( &ctx->cur ); |
if (!parse_uint( &ctx->cur, &uindex )) { |
report_error( ctx, "Expected literal integer" ); |
return FALSE; |
} |
bracket->last = (int) uindex; |
eat_opt_white( &ctx->cur ); |
} |
else { |
bracket->last = bracket->first; |
} |
cleanup: |
if (*ctx->cur != ']') { |
report_error( ctx, "Expected `]' or `..'" ); |
return FALSE; |
} |
ctx->cur++; |
return TRUE; |
} |
/* Parse register declaration. |
* <register_dcl> ::= <register_file_bracket_index> `]' | |
* <register_file_bracket_index> `..' <index> `]' |
*/ |
static boolean |
parse_register_dcl( |
struct translate_ctx *ctx, |
uint *file, |
struct parsed_dcl_bracket *brackets, |
int *num_brackets) |
{ |
const char *cur; |
*num_brackets = 0; |
if (!parse_register_file_bracket( ctx, file )) |
return FALSE; |
if (!parse_register_dcl_bracket( ctx, &brackets[0] )) |
return FALSE; |
*num_brackets = 1; |
cur = ctx->cur; |
eat_opt_white( &cur ); |
if (cur[0] == '[') { |
++cur; |
ctx->cur = cur; |
if (!parse_register_dcl_bracket( ctx, &brackets[1] )) |
return FALSE; |
/* for geometry shader we don't really care about |
* the first brackets it's always the size of the |
* input primitive. so we want to declare just |
* the index relevant to the semantics which is in |
* the second bracket */ |
if (ctx->processor == TGSI_PROCESSOR_GEOMETRY && *file == TGSI_FILE_INPUT) { |
brackets[0] = brackets[1]; |
*num_brackets = 1; |
} else { |
*num_brackets = 2; |
} |
} |
return TRUE; |
} |
/* Parse destination register operand.*/ |
static boolean |
parse_register_dst( |
struct translate_ctx *ctx, |
uint *file, |
struct parsed_bracket *brackets) |
{ |
brackets->ind_comp = TGSI_SWIZZLE_X; |
if (!parse_register_file_bracket( ctx, file )) |
return FALSE; |
if (!parse_register_bracket( ctx, brackets )) |
return FALSE; |
return TRUE; |
} |
static boolean |
parse_dst_operand( |
struct translate_ctx *ctx, |
struct tgsi_full_dst_register *dst ) |
{ |
uint file; |
uint writemask; |
const char *cur; |
struct parsed_bracket bracket[2]; |
int parsed_opt_brackets; |
if (!parse_register_dst( ctx, &file, &bracket[0] )) |
return FALSE; |
if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets)) |
return FALSE; |
cur = ctx->cur; |
eat_opt_white( &cur ); |
if (!parse_opt_writemask( ctx, &writemask )) |
return FALSE; |
dst->Register.File = file; |
if (parsed_opt_brackets) { |
dst->Register.Dimension = 1; |
dst->Dimension.Indirect = 0; |
dst->Dimension.Dimension = 0; |
dst->Dimension.Index = bracket[0].index; |
bracket[0] = bracket[1]; |
} |
dst->Register.Index = bracket[0].index; |
dst->Register.WriteMask = writemask; |
if (bracket[0].ind_file != TGSI_FILE_NULL) { |
dst->Register.Indirect = 1; |
dst->Indirect.File = bracket[0].ind_file; |
dst->Indirect.Index = bracket[0].ind_index; |
dst->Indirect.Swizzle = bracket[0].ind_comp; |
dst->Indirect.ArrayID = bracket[0].ind_array; |
} |
return TRUE; |
} |
static boolean |
parse_optional_swizzle( |
struct translate_ctx *ctx, |
uint swizzle[4], |
boolean *parsed_swizzle ) |
{ |
const char *cur = ctx->cur; |
*parsed_swizzle = FALSE; |
eat_opt_white( &cur ); |
if (*cur == '.') { |
uint i; |
cur++; |
eat_opt_white( &cur ); |
for (i = 0; i < 4; i++) { |
if (uprcase( *cur ) == 'X') |
swizzle[i] = TGSI_SWIZZLE_X; |
else if (uprcase( *cur ) == 'Y') |
swizzle[i] = TGSI_SWIZZLE_Y; |
else if (uprcase( *cur ) == 'Z') |
swizzle[i] = TGSI_SWIZZLE_Z; |
else if (uprcase( *cur ) == 'W') |
swizzle[i] = TGSI_SWIZZLE_W; |
else { |
report_error( ctx, "Expected register swizzle component `x', `y', `z' or `w'" ); |
return FALSE; |
} |
cur++; |
} |
*parsed_swizzle = TRUE; |
ctx->cur = cur; |
} |
return TRUE; |
} |
static boolean |
parse_src_operand( |
struct translate_ctx *ctx, |
struct tgsi_full_src_register *src ) |
{ |
uint file; |
uint swizzle[4]; |
boolean parsed_swizzle; |
struct parsed_bracket bracket[2]; |
int parsed_opt_brackets; |
if (*ctx->cur == '-') { |
ctx->cur++; |
eat_opt_white( &ctx->cur ); |
src->Register.Negate = 1; |
} |
if (*ctx->cur == '|') { |
ctx->cur++; |
eat_opt_white( &ctx->cur ); |
src->Register.Absolute = 1; |
} |
if (!parse_register_src(ctx, &file, &bracket[0])) |
return FALSE; |
if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets)) |
return FALSE; |
src->Register.File = file; |
if (parsed_opt_brackets) { |
src->Register.Dimension = 1; |
src->Dimension.Indirect = 0; |
src->Dimension.Dimension = 0; |
src->Dimension.Index = bracket[0].index; |
bracket[0] = bracket[1]; |
} |
src->Register.Index = bracket[0].index; |
if (bracket[0].ind_file != TGSI_FILE_NULL) { |
src->Register.Indirect = 1; |
src->Indirect.File = bracket[0].ind_file; |
src->Indirect.Index = bracket[0].ind_index; |
src->Indirect.Swizzle = bracket[0].ind_comp; |
src->Indirect.ArrayID = bracket[0].ind_array; |
} |
/* Parse optional swizzle. |
*/ |
if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) { |
if (parsed_swizzle) { |
src->Register.SwizzleX = swizzle[0]; |
src->Register.SwizzleY = swizzle[1]; |
src->Register.SwizzleZ = swizzle[2]; |
src->Register.SwizzleW = swizzle[3]; |
} |
} |
if (src->Register.Absolute) { |
eat_opt_white( &ctx->cur ); |
if (*ctx->cur != '|') { |
report_error( ctx, "Expected `|'" ); |
return FALSE; |
} |
ctx->cur++; |
} |
return TRUE; |
} |
static boolean |
match_inst(const char **pcur, |
unsigned *saturate, |
const struct tgsi_opcode_info *info) |
{ |
const char *cur = *pcur; |
/* simple case: the whole string matches the instruction name */ |
if (str_match_nocase_whole(&cur, info->mnemonic)) { |
*pcur = cur; |
*saturate = TGSI_SAT_NONE; |
return TRUE; |
} |
if (str_match_no_case(&cur, info->mnemonic)) { |
/* the instruction has a suffix, figure it out */ |
if (str_match_nocase_whole(&cur, "_SAT")) { |
*pcur = cur; |
*saturate = TGSI_SAT_ZERO_ONE; |
return TRUE; |
} |
if (str_match_nocase_whole(&cur, "_SATNV")) { |
*pcur = cur; |
*saturate = TGSI_SAT_MINUS_PLUS_ONE; |
return TRUE; |
} |
} |
return FALSE; |
} |
static boolean |
parse_instruction( |
struct translate_ctx *ctx, |
boolean has_label ) |
{ |
uint i; |
uint saturate = TGSI_SAT_NONE; |
const struct tgsi_opcode_info *info; |
struct tgsi_full_instruction inst; |
const char *cur; |
uint advance; |
inst = tgsi_default_full_instruction(); |
/* Parse predicate. |
*/ |
eat_opt_white( &ctx->cur ); |
if (*ctx->cur == '(') { |
uint file; |
int index; |
uint swizzle[4]; |
boolean parsed_swizzle; |
inst.Instruction.Predicate = 1; |
ctx->cur++; |
if (*ctx->cur == '!') { |
ctx->cur++; |
inst.Predicate.Negate = 1; |
} |
if (!parse_register_1d( ctx, &file, &index )) |
return FALSE; |
if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) { |
if (parsed_swizzle) { |
inst.Predicate.SwizzleX = swizzle[0]; |
inst.Predicate.SwizzleY = swizzle[1]; |
inst.Predicate.SwizzleZ = swizzle[2]; |
inst.Predicate.SwizzleW = swizzle[3]; |
} |
} |
if (*ctx->cur != ')') { |
report_error( ctx, "Expected `)'" ); |
return FALSE; |
} |
ctx->cur++; |
} |
/* Parse instruction name. |
*/ |
eat_opt_white( &ctx->cur ); |
for (i = 0; i < TGSI_OPCODE_LAST; i++) { |
cur = ctx->cur; |
info = tgsi_get_opcode_info( i ); |
if (match_inst(&cur, &saturate, info)) { |
if (info->num_dst + info->num_src + info->is_tex == 0) { |
ctx->cur = cur; |
break; |
} |
else if (*cur == '\0' || eat_white( &cur )) { |
ctx->cur = cur; |
break; |
} |
} |
} |
if (i == TGSI_OPCODE_LAST) { |
if (has_label) |
report_error( ctx, "Unknown opcode" ); |
else |
report_error( ctx, "Expected `DCL', `IMM' or a label" ); |
return FALSE; |
} |
inst.Instruction.Opcode = i; |
inst.Instruction.Saturate = saturate; |
inst.Instruction.NumDstRegs = info->num_dst; |
inst.Instruction.NumSrcRegs = info->num_src; |
if (i >= TGSI_OPCODE_SAMPLE && i <= TGSI_OPCODE_GATHER4) { |
/* |
* These are not considered tex opcodes here (no additional |
* target argument) however we're required to set the Texture |
* bit so we can set the number of tex offsets (offsets aren't |
* actually handled here yet in any case). |
*/ |
inst.Instruction.Texture = 1; |
inst.Texture.Texture = TGSI_TEXTURE_UNKNOWN; |
} |
/* Parse instruction operands. |
*/ |
for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) { |
if (i > 0) { |
eat_opt_white( &ctx->cur ); |
if (*ctx->cur != ',') { |
report_error( ctx, "Expected `,'" ); |
return FALSE; |
} |
ctx->cur++; |
eat_opt_white( &ctx->cur ); |
} |
if (i < info->num_dst) { |
if (!parse_dst_operand( ctx, &inst.Dst[i] )) |
return FALSE; |
} |
else if (i < info->num_dst + info->num_src) { |
if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] )) |
return FALSE; |
} |
else { |
uint j; |
for (j = 0; j < TGSI_TEXTURE_COUNT; j++) { |
if (str_match_nocase_whole( &ctx->cur, tgsi_texture_names[j] )) { |
inst.Instruction.Texture = 1; |
inst.Texture.Texture = j; |
break; |
} |
} |
if (j == TGSI_TEXTURE_COUNT) { |
report_error( ctx, "Expected texture target" ); |
return FALSE; |
} |
} |
} |
cur = ctx->cur; |
eat_opt_white( &cur ); |
if (info->is_branch && *cur == ':') { |
uint target; |
cur++; |
eat_opt_white( &cur ); |
if (!parse_uint( &cur, &target )) { |
report_error( ctx, "Expected a label" ); |
return FALSE; |
} |
inst.Instruction.Label = 1; |
inst.Label.Label = target; |
ctx->cur = cur; |
} |
advance = tgsi_build_full_instruction( |
&inst, |
ctx->tokens_cur, |
ctx->header, |
(uint) (ctx->tokens_end - ctx->tokens_cur) ); |
if (advance == 0) |
return FALSE; |
ctx->tokens_cur += advance; |
return TRUE; |
} |
/* parses a 4-touple of the form {x, y, z, w} |
* where x, y, z, w are numbers */ |
static boolean parse_immediate_data(struct translate_ctx *ctx, unsigned type, |
union tgsi_immediate_data *values) |
{ |
unsigned i; |
int ret; |
eat_opt_white( &ctx->cur ); |
if (*ctx->cur != '{') { |
report_error( ctx, "Expected `{'" ); |
return FALSE; |
} |
ctx->cur++; |
for (i = 0; i < 4; i++) { |
eat_opt_white( &ctx->cur ); |
if (i > 0) { |
if (*ctx->cur != ',') { |
report_error( ctx, "Expected `,'" ); |
return FALSE; |
} |
ctx->cur++; |
eat_opt_white( &ctx->cur ); |
} |
switch (type) { |
case TGSI_IMM_FLOAT32: |
ret = parse_float(&ctx->cur, &values[i].Float); |
break; |
case TGSI_IMM_UINT32: |
ret = parse_uint(&ctx->cur, &values[i].Uint); |
break; |
case TGSI_IMM_INT32: |
ret = parse_int(&ctx->cur, &values[i].Int); |
break; |
default: |
assert(0); |
ret = FALSE; |
break; |
} |
if (!ret) { |
report_error( ctx, "Expected immediate constant" ); |
return FALSE; |
} |
} |
eat_opt_white( &ctx->cur ); |
if (*ctx->cur != '}') { |
report_error( ctx, "Expected `}'" ); |
return FALSE; |
} |
ctx->cur++; |
return TRUE; |
} |
static boolean parse_declaration( struct translate_ctx *ctx ) |
{ |
struct tgsi_full_declaration decl; |
uint file; |
struct parsed_dcl_bracket brackets[2]; |
int num_brackets; |
uint writemask; |
const char *cur, *cur2; |
uint advance; |
boolean is_vs_input; |
if (!eat_white( &ctx->cur )) { |
report_error( ctx, "Syntax error" ); |
return FALSE; |
} |
if (!parse_register_dcl( ctx, &file, brackets, &num_brackets)) |
return FALSE; |
if (!parse_opt_writemask( ctx, &writemask )) |
return FALSE; |
decl = tgsi_default_full_declaration(); |
decl.Declaration.File = file; |
decl.Declaration.UsageMask = writemask; |
if (num_brackets == 1) { |
decl.Range.First = brackets[0].first; |
decl.Range.Last = brackets[0].last; |
} else { |
decl.Range.First = brackets[1].first; |
decl.Range.Last = brackets[1].last; |
decl.Declaration.Dimension = 1; |
decl.Dim.Index2D = brackets[0].first; |
} |
is_vs_input = (file == TGSI_FILE_INPUT && |
ctx->processor == TGSI_PROCESSOR_VERTEX); |
cur = ctx->cur; |
eat_opt_white( &cur ); |
if (*cur == ',') { |
cur2 = cur; |
cur2++; |
eat_opt_white( &cur2 ); |
if (str_match_nocase_whole( &cur2, "ARRAY" )) { |
int arrayid; |
if (*cur2 != '(') { |
report_error( ctx, "Expected `('" ); |
return FALSE; |
} |
cur2++; |
eat_opt_white( &cur2 ); |
if (!parse_int( &cur2, &arrayid )) { |
report_error( ctx, "Expected `,'" ); |
return FALSE; |
} |
eat_opt_white( &cur2 ); |
if (*cur2 != ')') { |
report_error( ctx, "Expected `)'" ); |
return FALSE; |
} |
cur2++; |
decl.Declaration.Array = 1; |
decl.Array.ArrayID = arrayid; |
ctx->cur = cur = cur2; |
} |
} |
if (*cur == ',' && !is_vs_input) { |
uint i, j; |
cur++; |
eat_opt_white( &cur ); |
if (file == TGSI_FILE_RESOURCE) { |
for (i = 0; i < TGSI_TEXTURE_COUNT; i++) { |
if (str_match_nocase_whole(&cur, tgsi_texture_names[i])) { |
decl.Resource.Resource = i; |
break; |
} |
} |
if (i == TGSI_TEXTURE_COUNT) { |
report_error(ctx, "Expected texture target"); |
return FALSE; |
} |
cur2 = cur; |
eat_opt_white(&cur2); |
while (*cur2 == ',') { |
cur2++; |
eat_opt_white(&cur2); |
if (str_match_nocase_whole(&cur2, "RAW")) { |
decl.Resource.Raw = 1; |
} else if (str_match_nocase_whole(&cur2, "WR")) { |
decl.Resource.Writable = 1; |
} else { |
break; |
} |
cur = cur2; |
eat_opt_white(&cur2); |
} |
ctx->cur = cur; |
} else if (file == TGSI_FILE_SAMPLER_VIEW) { |
for (i = 0; i < TGSI_TEXTURE_COUNT; i++) { |
if (str_match_nocase_whole(&cur, tgsi_texture_names[i])) { |
decl.SamplerView.Resource = i; |
break; |
} |
} |
if (i == TGSI_TEXTURE_COUNT) { |
report_error(ctx, "Expected texture target"); |
return FALSE; |
} |
eat_opt_white( &cur ); |
if (*cur != ',') { |
report_error( ctx, "Expected `,'" ); |
return FALSE; |
} |
++cur; |
eat_opt_white( &cur ); |
for (j = 0; j < 4; ++j) { |
for (i = 0; i < PIPE_TYPE_COUNT; ++i) { |
if (str_match_nocase_whole(&cur, tgsi_type_names[i])) { |
switch (j) { |
case 0: |
decl.SamplerView.ReturnTypeX = i; |
break; |
case 1: |
decl.SamplerView.ReturnTypeY = i; |
break; |
case 2: |
decl.SamplerView.ReturnTypeZ = i; |
break; |
case 3: |
decl.SamplerView.ReturnTypeW = i; |
break; |
default: |
assert(0); |
} |
break; |
} |
} |
if (i == PIPE_TYPE_COUNT) { |
if (j == 0 || j > 2) { |
report_error(ctx, "Expected type name"); |
return FALSE; |
} |
break; |
} else { |
cur2 = cur; |
eat_opt_white( &cur2 ); |
if (*cur2 == ',') { |
cur2++; |
eat_opt_white( &cur2 ); |
cur = cur2; |
continue; |
} else |
break; |
} |
} |
if (j < 4) { |
decl.SamplerView.ReturnTypeY = |
decl.SamplerView.ReturnTypeZ = |
decl.SamplerView.ReturnTypeW = |
decl.SamplerView.ReturnTypeX; |
} |
ctx->cur = cur; |
} else { |
if (str_match_nocase_whole(&cur, "LOCAL")) { |
decl.Declaration.Local = 1; |
ctx->cur = cur; |
} |
cur = ctx->cur; |
eat_opt_white( &cur ); |
if (*cur == ',') { |
cur++; |
eat_opt_white( &cur ); |
for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) { |
if (str_match_nocase_whole(&cur, tgsi_semantic_names[i])) { |
uint index; |
cur2 = cur; |
eat_opt_white( &cur2 ); |
if (*cur2 == '[') { |
cur2++; |
eat_opt_white( &cur2 ); |
if (!parse_uint( &cur2, &index )) { |
report_error( ctx, "Expected literal integer" ); |
return FALSE; |
} |
eat_opt_white( &cur2 ); |
if (*cur2 != ']') { |
report_error( ctx, "Expected `]'" ); |
return FALSE; |
} |
cur2++; |
decl.Semantic.Index = index; |
cur = cur2; |
} |
decl.Declaration.Semantic = 1; |
decl.Semantic.Name = i; |
ctx->cur = cur; |
break; |
} |
} |
} |
} |
} |
cur = ctx->cur; |
eat_opt_white( &cur ); |
if (*cur == ',' && !is_vs_input) { |
uint i; |
cur++; |
eat_opt_white( &cur ); |
for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) { |
if (str_match_nocase_whole( &cur, tgsi_interpolate_names[i] )) { |
decl.Declaration.Interpolate = 1; |
decl.Interp.Interpolate = i; |
ctx->cur = cur; |
break; |
} |
} |
if (i == TGSI_INTERPOLATE_COUNT) { |
report_error( ctx, "Expected semantic or interpolate attribute" ); |
return FALSE; |
} |
} |
advance = tgsi_build_full_declaration( |
&decl, |
ctx->tokens_cur, |
ctx->header, |
(uint) (ctx->tokens_end - ctx->tokens_cur) ); |
if (advance == 0) |
return FALSE; |
ctx->tokens_cur += advance; |
return TRUE; |
} |
static boolean parse_immediate( struct translate_ctx *ctx ) |
{ |
struct tgsi_full_immediate imm; |
uint advance; |
int type; |
if (*ctx->cur == '[') { |
uint uindex; |
++ctx->cur; |
eat_opt_white( &ctx->cur ); |
if (!parse_uint( &ctx->cur, &uindex )) { |
report_error( ctx, "Expected literal unsigned integer" ); |
return FALSE; |
} |
if (uindex != ctx->num_immediates) { |
report_error( ctx, "Immediates must be sorted" ); |
return FALSE; |
} |
eat_opt_white( &ctx->cur ); |
if (*ctx->cur != ']') { |
report_error( ctx, "Expected `]'" ); |
return FALSE; |
} |
ctx->cur++; |
} |
if (!eat_white( &ctx->cur )) { |
report_error( ctx, "Syntax error" ); |
return FALSE; |
} |
for (type = 0; type < Elements(tgsi_immediate_type_names); ++type) { |
if (str_match_nocase_whole(&ctx->cur, tgsi_immediate_type_names[type])) |
break; |
} |
if (type == Elements(tgsi_immediate_type_names)) { |
report_error( ctx, "Expected immediate type" ); |
return FALSE; |
} |
imm = tgsi_default_full_immediate(); |
imm.Immediate.NrTokens += 4; |
imm.Immediate.DataType = type; |
parse_immediate_data(ctx, type, imm.u); |
advance = tgsi_build_full_immediate( |
&imm, |
ctx->tokens_cur, |
ctx->header, |
(uint) (ctx->tokens_end - ctx->tokens_cur) ); |
if (advance == 0) |
return FALSE; |
ctx->tokens_cur += advance; |
ctx->num_immediates++; |
return TRUE; |
} |
static boolean |
parse_primitive( const char **pcur, uint *primitive ) |
{ |
uint i; |
for (i = 0; i < PIPE_PRIM_MAX; i++) { |
const char *cur = *pcur; |
if (str_match_nocase_whole( &cur, tgsi_primitive_names[i])) { |
*primitive = i; |
*pcur = cur; |
return TRUE; |
} |
} |
return FALSE; |
} |
static boolean |
parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin ) |
{ |
uint i; |
for (i = 0; i < Elements(tgsi_fs_coord_origin_names); i++) { |
const char *cur = *pcur; |
if (str_match_nocase_whole( &cur, tgsi_fs_coord_origin_names[i])) { |
*fs_coord_origin = i; |
*pcur = cur; |
return TRUE; |
} |
} |
return FALSE; |
} |
static boolean |
parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center ) |
{ |
uint i; |
for (i = 0; i < Elements(tgsi_fs_coord_pixel_center_names); i++) { |
const char *cur = *pcur; |
if (str_match_nocase_whole( &cur, tgsi_fs_coord_pixel_center_names[i])) { |
*fs_coord_pixel_center = i; |
*pcur = cur; |
return TRUE; |
} |
} |
return FALSE; |
} |
static boolean parse_property( struct translate_ctx *ctx ) |
{ |
struct tgsi_full_property prop; |
uint property_name; |
uint values[8]; |
uint advance; |
char id[64]; |
if (!eat_white( &ctx->cur )) { |
report_error( ctx, "Syntax error" ); |
return FALSE; |
} |
if (!parse_identifier( &ctx->cur, id )) { |
report_error( ctx, "Syntax error" ); |
return FALSE; |
} |
for (property_name = 0; property_name < TGSI_PROPERTY_COUNT; |
++property_name) { |
if (streq_nocase_uprcase(tgsi_property_names[property_name], id)) { |
break; |
} |
} |
if (property_name >= TGSI_PROPERTY_COUNT) { |
debug_printf( "\nError: Unknown property : '%s'", id ); |
return FALSE; |
} |
eat_opt_white( &ctx->cur ); |
switch(property_name) { |
case TGSI_PROPERTY_GS_INPUT_PRIM: |
case TGSI_PROPERTY_GS_OUTPUT_PRIM: |
if (!parse_primitive(&ctx->cur, &values[0] )) { |
report_error( ctx, "Unknown primitive name as property!" ); |
return FALSE; |
} |
if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM && |
ctx->processor == TGSI_PROCESSOR_GEOMETRY) { |
ctx->implied_array_size = u_vertices_per_prim(values[0]); |
} |
break; |
case TGSI_PROPERTY_FS_COORD_ORIGIN: |
if (!parse_fs_coord_origin(&ctx->cur, &values[0] )) { |
report_error( ctx, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" ); |
return FALSE; |
} |
break; |
case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: |
if (!parse_fs_coord_pixel_center(&ctx->cur, &values[0] )) { |
report_error( ctx, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" ); |
return FALSE; |
} |
break; |
case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS: |
default: |
if (!parse_uint(&ctx->cur, &values[0] )) { |
report_error( ctx, "Expected unsigned integer as property!" ); |
return FALSE; |
} |
} |
prop = tgsi_default_full_property(); |
prop.Property.PropertyName = property_name; |
prop.Property.NrTokens += 1; |
prop.u[0].Data = values[0]; |
advance = tgsi_build_full_property( |
&prop, |
ctx->tokens_cur, |
ctx->header, |
(uint) (ctx->tokens_end - ctx->tokens_cur) ); |
if (advance == 0) |
return FALSE; |
ctx->tokens_cur += advance; |
return TRUE; |
} |
static boolean translate( struct translate_ctx *ctx ) |
{ |
eat_opt_white( &ctx->cur ); |
if (!parse_header( ctx )) |
return FALSE; |
while (*ctx->cur != '\0') { |
uint label_val = 0; |
if (!eat_white( &ctx->cur )) { |
report_error( ctx, "Syntax error" ); |
return FALSE; |
} |
if (*ctx->cur == '\0') |
break; |
if (parse_label( ctx, &label_val )) { |
if (!parse_instruction( ctx, TRUE )) |
return FALSE; |
} |
else if (str_match_nocase_whole( &ctx->cur, "DCL" )) { |
if (!parse_declaration( ctx )) |
return FALSE; |
} |
else if (str_match_nocase_whole( &ctx->cur, "IMM" )) { |
if (!parse_immediate( ctx )) |
return FALSE; |
} |
else if (str_match_nocase_whole( &ctx->cur, "PROPERTY" )) { |
if (!parse_property( ctx )) |
return FALSE; |
} |
else if (!parse_instruction( ctx, FALSE )) { |
return FALSE; |
} |
} |
return TRUE; |
} |
boolean |
tgsi_text_translate( |
const char *text, |
struct tgsi_token *tokens, |
uint num_tokens ) |
{ |
struct translate_ctx ctx = {0}; |
ctx.text = text; |
ctx.cur = text; |
ctx.tokens = tokens; |
ctx.tokens_cur = tokens; |
ctx.tokens_end = tokens + num_tokens; |
if (!translate( &ctx )) |
return FALSE; |
return tgsi_sanity_check( tokens ); |
} |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_text.h |
---|
0,0 → 1,49 |
/************************************************************************** |
* |
* Copyright 2008 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. |
* |
**************************************************************************/ |
#ifndef TGSI_TEXT_H |
#define TGSI_TEXT_H |
#if defined __cplusplus |
extern "C" { |
#endif |
#include "pipe/p_compiler.h" |
struct tgsi_token; |
boolean |
tgsi_text_translate( |
const char *text, |
struct tgsi_token *tokens, |
uint num_tokens ); |
#if defined __cplusplus |
} |
#endif |
#endif /* TGSI_TEXT_H */ |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_transform.c |
---|
0,0 → 1,250 |
/************************************************************************** |
* |
* Copyright 2008 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. |
* |
**************************************************************************/ |
/** |
* TGSI program transformation utility. |
* |
* Authors: Brian Paul |
*/ |
#include "util/u_debug.h" |
#include "tgsi_transform.h" |
static void |
emit_instruction(struct tgsi_transform_context *ctx, |
const struct tgsi_full_instruction *inst) |
{ |
uint ti = ctx->ti; |
ti += tgsi_build_full_instruction(inst, |
ctx->tokens_out + ti, |
ctx->header, |
ctx->max_tokens_out - ti); |
ctx->ti = ti; |
} |
static void |
emit_declaration(struct tgsi_transform_context *ctx, |
const struct tgsi_full_declaration *decl) |
{ |
uint ti = ctx->ti; |
ti += tgsi_build_full_declaration(decl, |
ctx->tokens_out + ti, |
ctx->header, |
ctx->max_tokens_out - ti); |
ctx->ti = ti; |
} |
static void |
emit_immediate(struct tgsi_transform_context *ctx, |
const struct tgsi_full_immediate *imm) |
{ |
uint ti = ctx->ti; |
ti += tgsi_build_full_immediate(imm, |
ctx->tokens_out + ti, |
ctx->header, |
ctx->max_tokens_out - ti); |
ctx->ti = ti; |
} |
static void |
emit_property(struct tgsi_transform_context *ctx, |
const struct tgsi_full_property *prop) |
{ |
uint ti = ctx->ti; |
ti += tgsi_build_full_property(prop, |
ctx->tokens_out + ti, |
ctx->header, |
ctx->max_tokens_out - ti); |
ctx->ti = ti; |
} |
/** |
* Apply user-defined transformations to the input shader to produce |
* the output shader. |
* For example, a register search-and-replace operation could be applied |
* by defining a transform_instruction() callback that examined and changed |
* the instruction src/dest regs. |
* |
* \return number of tokens emitted |
*/ |
int |
tgsi_transform_shader(const struct tgsi_token *tokens_in, |
struct tgsi_token *tokens_out, |
uint max_tokens_out, |
struct tgsi_transform_context *ctx) |
{ |
uint procType; |
/* input shader */ |
struct tgsi_parse_context parse; |
/* output shader */ |
struct tgsi_processor *processor; |
/** |
** callback context init |
**/ |
ctx->emit_instruction = emit_instruction; |
ctx->emit_declaration = emit_declaration; |
ctx->emit_immediate = emit_immediate; |
ctx->emit_property = emit_property; |
ctx->tokens_out = tokens_out; |
ctx->max_tokens_out = max_tokens_out; |
/** |
** Setup to begin parsing input shader |
**/ |
if (tgsi_parse_init( &parse, tokens_in ) != TGSI_PARSE_OK) { |
debug_printf("tgsi_parse_init() failed in tgsi_transform_shader()!\n"); |
return -1; |
} |
procType = parse.FullHeader.Processor.Processor; |
assert(procType == TGSI_PROCESSOR_FRAGMENT || |
procType == TGSI_PROCESSOR_VERTEX || |
procType == TGSI_PROCESSOR_GEOMETRY); |
/** |
** Setup output shader |
**/ |
ctx->header = (struct tgsi_header *)tokens_out; |
*ctx->header = tgsi_build_header(); |
processor = (struct tgsi_processor *) (tokens_out + 1); |
*processor = tgsi_build_processor( procType, ctx->header ); |
ctx->ti = 2; |
/** |
** Loop over incoming program tokens/instructions |
*/ |
while( !tgsi_parse_end_of_tokens( &parse ) ) { |
tgsi_parse_token( &parse ); |
switch( parse.FullToken.Token.Type ) { |
case TGSI_TOKEN_TYPE_INSTRUCTION: |
{ |
struct tgsi_full_instruction *fullinst |
= &parse.FullToken.FullInstruction; |
if (ctx->transform_instruction) |
ctx->transform_instruction(ctx, fullinst); |
else |
ctx->emit_instruction(ctx, fullinst); |
} |
break; |
case TGSI_TOKEN_TYPE_DECLARATION: |
{ |
struct tgsi_full_declaration *fulldecl |
= &parse.FullToken.FullDeclaration; |
if (ctx->transform_declaration) |
ctx->transform_declaration(ctx, fulldecl); |
else |
ctx->emit_declaration(ctx, fulldecl); |
} |
break; |
case TGSI_TOKEN_TYPE_IMMEDIATE: |
{ |
struct tgsi_full_immediate *fullimm |
= &parse.FullToken.FullImmediate; |
if (ctx->transform_immediate) |
ctx->transform_immediate(ctx, fullimm); |
else |
ctx->emit_immediate(ctx, fullimm); |
} |
break; |
case TGSI_TOKEN_TYPE_PROPERTY: |
{ |
struct tgsi_full_property *fullprop |
= &parse.FullToken.FullProperty; |
if (ctx->transform_property) |
ctx->transform_property(ctx, fullprop); |
else |
ctx->emit_property(ctx, fullprop); |
} |
break; |
default: |
assert( 0 ); |
} |
} |
if (ctx->epilog) { |
ctx->epilog(ctx); |
} |
tgsi_parse_free (&parse); |
return ctx->ti; |
} |
#include "tgsi_text.h" |
extern int tgsi_transform_foo( struct tgsi_token *tokens_out, |
uint max_tokens_out ); |
/* This function exists only so that tgsi_text_translate() doesn't get |
* magic-ed out of the libtgsi.a archive by the build system. Don't |
* remove unless you know this has been fixed - check on mingw/scons |
* builds as well. |
*/ |
int |
tgsi_transform_foo( struct tgsi_token *tokens_out, |
uint max_tokens_out ) |
{ |
const char *text = |
"FRAG\n" |
"DCL IN[0], COLOR, CONSTANT\n" |
"DCL OUT[0], COLOR\n" |
" 0: MOV OUT[0], IN[0]\n" |
" 1: END"; |
return tgsi_text_translate( text, |
tokens_out, |
max_tokens_out ); |
} |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_transform.h |
---|
0,0 → 1,96 |
/************************************************************************** |
* |
* Copyright 2008 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. |
* |
**************************************************************************/ |
#ifndef TGSI_TRANSFORM_H |
#define TGSI_TRANSFORM_H |
#include "pipe/p_shader_tokens.h" |
#include "tgsi/tgsi_parse.h" |
#include "tgsi/tgsi_build.h" |
/** |
* Subclass this to add caller-specific data |
*/ |
struct tgsi_transform_context |
{ |
/**** PUBLIC ***/ |
/** |
* User-defined callbacks invoked per instruction. |
*/ |
void (*transform_instruction)(struct tgsi_transform_context *ctx, |
struct tgsi_full_instruction *inst); |
void (*transform_declaration)(struct tgsi_transform_context *ctx, |
struct tgsi_full_declaration *decl); |
void (*transform_immediate)(struct tgsi_transform_context *ctx, |
struct tgsi_full_immediate *imm); |
void (*transform_property)(struct tgsi_transform_context *ctx, |
struct tgsi_full_property *prop); |
/** |
* Called at end of input program to allow caller to append extra |
* instructions. Return number of tokens emitted. |
*/ |
void (*epilog)(struct tgsi_transform_context *ctx); |
/*** PRIVATE ***/ |
/** |
* These are setup by tgsi_transform_shader() and cannot be overridden. |
* Meant to be called from in the above user callback functions. |
*/ |
void (*emit_instruction)(struct tgsi_transform_context *ctx, |
const struct tgsi_full_instruction *inst); |
void (*emit_declaration)(struct tgsi_transform_context *ctx, |
const struct tgsi_full_declaration *decl); |
void (*emit_immediate)(struct tgsi_transform_context *ctx, |
const struct tgsi_full_immediate *imm); |
void (*emit_property)(struct tgsi_transform_context *ctx, |
const struct tgsi_full_property *prop); |
struct tgsi_header *header; |
uint max_tokens_out; |
struct tgsi_token *tokens_out; |
uint ti; |
}; |
extern int |
tgsi_transform_shader(const struct tgsi_token *tokens_in, |
struct tgsi_token *tokens_out, |
uint max_tokens_out, |
struct tgsi_transform_context *ctx); |
#endif /* TGSI_TRANSFORM_H */ |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_ureg.c |
---|
0,0 → 1,1795 |
/************************************************************************** |
* |
* Copyright 2009-2010 VMware, Inc. |
* 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 VMWARE, INC 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 "pipe/p_context.h" |
#include "pipe/p_state.h" |
#include "tgsi/tgsi_ureg.h" |
#include "tgsi/tgsi_build.h" |
#include "tgsi/tgsi_info.h" |
#include "tgsi/tgsi_dump.h" |
#include "tgsi/tgsi_sanity.h" |
#include "util/u_debug.h" |
#include "util/u_memory.h" |
#include "util/u_math.h" |
#include "util/u_bitmask.h" |
union tgsi_any_token { |
struct tgsi_header header; |
struct tgsi_processor processor; |
struct tgsi_token token; |
struct tgsi_property prop; |
struct tgsi_property_data prop_data; |
struct tgsi_declaration decl; |
struct tgsi_declaration_range decl_range; |
struct tgsi_declaration_dimension decl_dim; |
struct tgsi_declaration_interp decl_interp; |
struct tgsi_declaration_semantic decl_semantic; |
struct tgsi_declaration_sampler_view decl_sampler_view; |
struct tgsi_declaration_array array; |
struct tgsi_immediate imm; |
union tgsi_immediate_data imm_data; |
struct tgsi_instruction insn; |
struct tgsi_instruction_predicate insn_predicate; |
struct tgsi_instruction_label insn_label; |
struct tgsi_instruction_texture insn_texture; |
struct tgsi_texture_offset insn_texture_offset; |
struct tgsi_src_register src; |
struct tgsi_ind_register ind; |
struct tgsi_dimension dim; |
struct tgsi_dst_register dst; |
unsigned value; |
}; |
struct ureg_tokens { |
union tgsi_any_token *tokens; |
unsigned size; |
unsigned order; |
unsigned count; |
}; |
#define UREG_MAX_INPUT PIPE_MAX_ATTRIBS |
#define UREG_MAX_SYSTEM_VALUE PIPE_MAX_ATTRIBS |
#define UREG_MAX_OUTPUT PIPE_MAX_SHADER_OUTPUTS |
#define UREG_MAX_CONSTANT_RANGE 32 |
#define UREG_MAX_IMMEDIATE 256 |
#define UREG_MAX_ADDR 2 |
#define UREG_MAX_PRED 1 |
#define UREG_MAX_ARRAY_TEMPS 256 |
struct const_decl { |
struct { |
unsigned first; |
unsigned last; |
} constant_range[UREG_MAX_CONSTANT_RANGE]; |
unsigned nr_constant_ranges; |
}; |
#define DOMAIN_DECL 0 |
#define DOMAIN_INSN 1 |
struct ureg_program |
{ |
unsigned processor; |
struct pipe_context *pipe; |
struct { |
unsigned semantic_name; |
unsigned semantic_index; |
unsigned interp; |
unsigned char cylindrical_wrap; |
unsigned char centroid; |
} fs_input[UREG_MAX_INPUT]; |
unsigned nr_fs_inputs; |
unsigned vs_inputs[UREG_MAX_INPUT/32]; |
struct { |
unsigned index; |
unsigned semantic_name; |
unsigned semantic_index; |
} gs_input[UREG_MAX_INPUT]; |
unsigned nr_gs_inputs; |
struct { |
unsigned index; |
unsigned semantic_name; |
unsigned semantic_index; |
} system_value[UREG_MAX_SYSTEM_VALUE]; |
unsigned nr_system_values; |
struct { |
unsigned semantic_name; |
unsigned semantic_index; |
unsigned usage_mask; /* = TGSI_WRITEMASK_* */ |
} output[UREG_MAX_OUTPUT]; |
unsigned nr_outputs; |
struct { |
union { |
float f[4]; |
unsigned u[4]; |
int i[4]; |
} value; |
unsigned nr; |
unsigned type; |
} immediate[UREG_MAX_IMMEDIATE]; |
unsigned nr_immediates; |
struct ureg_src sampler[PIPE_MAX_SAMPLERS]; |
unsigned nr_samplers; |
struct { |
unsigned index; |
unsigned target; |
unsigned return_type_x; |
unsigned return_type_y; |
unsigned return_type_z; |
unsigned return_type_w; |
} sampler_view[PIPE_MAX_SHADER_SAMPLER_VIEWS]; |
unsigned nr_sampler_views; |
struct util_bitmask *free_temps; |
struct util_bitmask *local_temps; |
struct util_bitmask *decl_temps; |
unsigned nr_temps; |
unsigned array_temps[UREG_MAX_ARRAY_TEMPS]; |
unsigned nr_array_temps; |
struct const_decl const_decls; |
struct const_decl const_decls2D[PIPE_MAX_CONSTANT_BUFFERS]; |
unsigned property_gs_input_prim; |
unsigned property_gs_output_prim; |
unsigned property_gs_max_vertices; |
unsigned char property_fs_coord_origin; /* = TGSI_FS_COORD_ORIGIN_* */ |
unsigned char property_fs_coord_pixel_center; /* = TGSI_FS_COORD_PIXEL_CENTER_* */ |
unsigned char property_fs_color0_writes_all_cbufs; /* = TGSI_FS_COLOR0_WRITES_ALL_CBUFS * */ |
unsigned char property_fs_depth_layout; /* TGSI_FS_DEPTH_LAYOUT */ |
unsigned nr_addrs; |
unsigned nr_preds; |
unsigned nr_instructions; |
struct ureg_tokens domain[2]; |
}; |
static union tgsi_any_token error_tokens[32]; |
static void tokens_error( struct ureg_tokens *tokens ) |
{ |
if (tokens->tokens && tokens->tokens != error_tokens) |
FREE(tokens->tokens); |
tokens->tokens = error_tokens; |
tokens->size = Elements(error_tokens); |
tokens->count = 0; |
} |
static void tokens_expand( struct ureg_tokens *tokens, |
unsigned count ) |
{ |
unsigned old_size = tokens->size * sizeof(unsigned); |
if (tokens->tokens == error_tokens) { |
return; |
} |
while (tokens->count + count > tokens->size) { |
tokens->size = (1 << ++tokens->order); |
} |
tokens->tokens = REALLOC(tokens->tokens, |
old_size, |
tokens->size * sizeof(unsigned)); |
if (tokens->tokens == NULL) { |
tokens_error(tokens); |
} |
} |
static void set_bad( struct ureg_program *ureg ) |
{ |
tokens_error(&ureg->domain[0]); |
} |
static union tgsi_any_token *get_tokens( struct ureg_program *ureg, |
unsigned domain, |
unsigned count ) |
{ |
struct ureg_tokens *tokens = &ureg->domain[domain]; |
union tgsi_any_token *result; |
if (tokens->count + count > tokens->size) |
tokens_expand(tokens, count); |
result = &tokens->tokens[tokens->count]; |
tokens->count += count; |
return result; |
} |
static union tgsi_any_token *retrieve_token( struct ureg_program *ureg, |
unsigned domain, |
unsigned nr ) |
{ |
if (ureg->domain[domain].tokens == error_tokens) |
return &error_tokens[0]; |
return &ureg->domain[domain].tokens[nr]; |
} |
static INLINE struct ureg_dst |
ureg_dst_register( unsigned file, |
unsigned index ) |
{ |
struct ureg_dst dst; |
dst.File = file; |
dst.WriteMask = TGSI_WRITEMASK_XYZW; |
dst.Indirect = 0; |
dst.IndirectFile = TGSI_FILE_NULL; |
dst.IndirectIndex = 0; |
dst.IndirectSwizzle = 0; |
dst.Saturate = 0; |
dst.Predicate = 0; |
dst.PredNegate = 0; |
dst.PredSwizzleX = TGSI_SWIZZLE_X; |
dst.PredSwizzleY = TGSI_SWIZZLE_Y; |
dst.PredSwizzleZ = TGSI_SWIZZLE_Z; |
dst.PredSwizzleW = TGSI_SWIZZLE_W; |
dst.Index = index; |
dst.ArrayID = 0; |
return dst; |
} |
void |
ureg_property_gs_input_prim(struct ureg_program *ureg, |
unsigned input_prim) |
{ |
ureg->property_gs_input_prim = input_prim; |
} |
void |
ureg_property_gs_output_prim(struct ureg_program *ureg, |
unsigned output_prim) |
{ |
ureg->property_gs_output_prim = output_prim; |
} |
void |
ureg_property_gs_max_vertices(struct ureg_program *ureg, |
unsigned max_vertices) |
{ |
ureg->property_gs_max_vertices = max_vertices; |
} |
void |
ureg_property_fs_coord_origin(struct ureg_program *ureg, |
unsigned fs_coord_origin) |
{ |
ureg->property_fs_coord_origin = fs_coord_origin; |
} |
void |
ureg_property_fs_coord_pixel_center(struct ureg_program *ureg, |
unsigned fs_coord_pixel_center) |
{ |
ureg->property_fs_coord_pixel_center = fs_coord_pixel_center; |
} |
void |
ureg_property_fs_color0_writes_all_cbufs(struct ureg_program *ureg, |
unsigned fs_color0_writes_all_cbufs) |
{ |
ureg->property_fs_color0_writes_all_cbufs = fs_color0_writes_all_cbufs; |
} |
void |
ureg_property_fs_depth_layout(struct ureg_program *ureg, |
unsigned fs_depth_layout) |
{ |
ureg->property_fs_depth_layout = fs_depth_layout; |
} |
struct ureg_src |
ureg_DECL_fs_input_cyl_centroid(struct ureg_program *ureg, |
unsigned semantic_name, |
unsigned semantic_index, |
unsigned interp_mode, |
unsigned cylindrical_wrap, |
unsigned centroid) |
{ |
unsigned i; |
for (i = 0; i < ureg->nr_fs_inputs; i++) { |
if (ureg->fs_input[i].semantic_name == semantic_name && |
ureg->fs_input[i].semantic_index == semantic_index) { |
goto out; |
} |
} |
if (ureg->nr_fs_inputs < UREG_MAX_INPUT) { |
ureg->fs_input[i].semantic_name = semantic_name; |
ureg->fs_input[i].semantic_index = semantic_index; |
ureg->fs_input[i].interp = interp_mode; |
ureg->fs_input[i].cylindrical_wrap = cylindrical_wrap; |
ureg->fs_input[i].centroid = centroid; |
ureg->nr_fs_inputs++; |
} else { |
set_bad(ureg); |
} |
out: |
return ureg_src_register(TGSI_FILE_INPUT, i); |
} |
struct ureg_src |
ureg_DECL_vs_input( struct ureg_program *ureg, |
unsigned index ) |
{ |
assert(ureg->processor == TGSI_PROCESSOR_VERTEX); |
ureg->vs_inputs[index/32] |= 1 << (index % 32); |
return ureg_src_register( TGSI_FILE_INPUT, index ); |
} |
struct ureg_src |
ureg_DECL_gs_input(struct ureg_program *ureg, |
unsigned index, |
unsigned semantic_name, |
unsigned semantic_index) |
{ |
if (ureg->nr_gs_inputs < UREG_MAX_INPUT) { |
ureg->gs_input[ureg->nr_gs_inputs].index = index; |
ureg->gs_input[ureg->nr_gs_inputs].semantic_name = semantic_name; |
ureg->gs_input[ureg->nr_gs_inputs].semantic_index = semantic_index; |
ureg->nr_gs_inputs++; |
} else { |
set_bad(ureg); |
} |
/* XXX: Add suport for true 2D input registers. */ |
return ureg_src_register(TGSI_FILE_INPUT, index); |
} |
struct ureg_src |
ureg_DECL_system_value(struct ureg_program *ureg, |
unsigned index, |
unsigned semantic_name, |
unsigned semantic_index) |
{ |
if (ureg->nr_system_values < UREG_MAX_SYSTEM_VALUE) { |
ureg->system_value[ureg->nr_system_values].index = index; |
ureg->system_value[ureg->nr_system_values].semantic_name = semantic_name; |
ureg->system_value[ureg->nr_system_values].semantic_index = semantic_index; |
ureg->nr_system_values++; |
} else { |
set_bad(ureg); |
} |
return ureg_src_register(TGSI_FILE_SYSTEM_VALUE, index); |
} |
struct ureg_dst |
ureg_DECL_output_masked( struct ureg_program *ureg, |
unsigned name, |
unsigned index, |
unsigned usage_mask ) |
{ |
unsigned i; |
assert(usage_mask != 0); |
for (i = 0; i < ureg->nr_outputs; i++) { |
if (ureg->output[i].semantic_name == name && |
ureg->output[i].semantic_index == index) { |
ureg->output[i].usage_mask |= usage_mask; |
goto out; |
} |
} |
if (ureg->nr_outputs < UREG_MAX_OUTPUT) { |
ureg->output[i].semantic_name = name; |
ureg->output[i].semantic_index = index; |
ureg->output[i].usage_mask = usage_mask; |
ureg->nr_outputs++; |
} |
else { |
set_bad( ureg ); |
} |
out: |
return ureg_dst_register( TGSI_FILE_OUTPUT, i ); |
} |
struct ureg_dst |
ureg_DECL_output( struct ureg_program *ureg, |
unsigned name, |
unsigned index ) |
{ |
return ureg_DECL_output_masked(ureg, name, index, TGSI_WRITEMASK_XYZW); |
} |
/* Returns a new constant register. Keep track of which have been |
* referred to so that we can emit decls later. |
* |
* Constant operands declared with this function must be addressed |
* with a two-dimensional index. |
* |
* There is nothing in this code to bind this constant to any tracked |
* value or manage any constant_buffer contents -- that's the |
* resposibility of the calling code. |
*/ |
void |
ureg_DECL_constant2D(struct ureg_program *ureg, |
unsigned first, |
unsigned last, |
unsigned index2D) |
{ |
struct const_decl *decl = &ureg->const_decls2D[index2D]; |
assert(index2D < PIPE_MAX_CONSTANT_BUFFERS); |
if (decl->nr_constant_ranges < UREG_MAX_CONSTANT_RANGE) { |
uint i = decl->nr_constant_ranges++; |
decl->constant_range[i].first = first; |
decl->constant_range[i].last = last; |
} |
} |
/* A one-dimensional, depricated version of ureg_DECL_constant2D(). |
* |
* Constant operands declared with this function must be addressed |
* with a one-dimensional index. |
*/ |
struct ureg_src |
ureg_DECL_constant(struct ureg_program *ureg, |
unsigned index) |
{ |
struct const_decl *decl = &ureg->const_decls; |
unsigned minconst = index, maxconst = index; |
unsigned i; |
/* Inside existing range? |
*/ |
for (i = 0; i < decl->nr_constant_ranges; i++) { |
if (decl->constant_range[i].first <= index && |
decl->constant_range[i].last >= index) { |
goto out; |
} |
} |
/* Extend existing range? |
*/ |
for (i = 0; i < decl->nr_constant_ranges; i++) { |
if (decl->constant_range[i].last == index - 1) { |
decl->constant_range[i].last = index; |
goto out; |
} |
if (decl->constant_range[i].first == index + 1) { |
decl->constant_range[i].first = index; |
goto out; |
} |
minconst = MIN2(minconst, decl->constant_range[i].first); |
maxconst = MAX2(maxconst, decl->constant_range[i].last); |
} |
/* Create new range? |
*/ |
if (decl->nr_constant_ranges < UREG_MAX_CONSTANT_RANGE) { |
i = decl->nr_constant_ranges++; |
decl->constant_range[i].first = index; |
decl->constant_range[i].last = index; |
goto out; |
} |
/* Collapse all ranges down to one: |
*/ |
i = 0; |
decl->constant_range[0].first = minconst; |
decl->constant_range[0].last = maxconst; |
decl->nr_constant_ranges = 1; |
out: |
assert(i < decl->nr_constant_ranges); |
assert(decl->constant_range[i].first <= index); |
assert(decl->constant_range[i].last >= index); |
return ureg_src_register(TGSI_FILE_CONSTANT, index); |
} |
static struct ureg_dst alloc_temporary( struct ureg_program *ureg, |
boolean local ) |
{ |
unsigned i; |
/* Look for a released temporary. |
*/ |
for (i = util_bitmask_get_first_index(ureg->free_temps); |
i != UTIL_BITMASK_INVALID_INDEX; |
i = util_bitmask_get_next_index(ureg->free_temps, i + 1)) { |
if (util_bitmask_get(ureg->local_temps, i) == local) |
break; |
} |
/* Or allocate a new one. |
*/ |
if (i == UTIL_BITMASK_INVALID_INDEX) { |
i = ureg->nr_temps++; |
if (local) |
util_bitmask_set(ureg->local_temps, i); |
/* Start a new declaration when the local flag changes */ |
if (!i || util_bitmask_get(ureg->local_temps, i - 1) != local) |
util_bitmask_set(ureg->decl_temps, i); |
} |
util_bitmask_clear(ureg->free_temps, i); |
return ureg_dst_register( TGSI_FILE_TEMPORARY, i ); |
} |
struct ureg_dst ureg_DECL_temporary( struct ureg_program *ureg ) |
{ |
return alloc_temporary(ureg, FALSE); |
} |
struct ureg_dst ureg_DECL_local_temporary( struct ureg_program *ureg ) |
{ |
return alloc_temporary(ureg, TRUE); |
} |
struct ureg_dst ureg_DECL_array_temporary( struct ureg_program *ureg, |
unsigned size, |
boolean local ) |
{ |
unsigned i = ureg->nr_temps; |
struct ureg_dst dst = ureg_dst_register( TGSI_FILE_TEMPORARY, i ); |
if (local) |
util_bitmask_set(ureg->local_temps, i); |
/* Always start a new declaration at the start */ |
util_bitmask_set(ureg->decl_temps, i); |
ureg->nr_temps += size; |
/* and also at the end of the array */ |
util_bitmask_set(ureg->decl_temps, ureg->nr_temps); |
if (ureg->nr_array_temps < UREG_MAX_ARRAY_TEMPS) { |
ureg->array_temps[ureg->nr_array_temps++] = i; |
dst.ArrayID = ureg->nr_array_temps; |
} |
return dst; |
} |
void ureg_release_temporary( struct ureg_program *ureg, |
struct ureg_dst tmp ) |
{ |
if(tmp.File == TGSI_FILE_TEMPORARY) |
util_bitmask_set(ureg->free_temps, tmp.Index); |
} |
/* Allocate a new address register. |
*/ |
struct ureg_dst ureg_DECL_address( struct ureg_program *ureg ) |
{ |
if (ureg->nr_addrs < UREG_MAX_ADDR) |
return ureg_dst_register( TGSI_FILE_ADDRESS, ureg->nr_addrs++ ); |
assert( 0 ); |
return ureg_dst_register( TGSI_FILE_ADDRESS, 0 ); |
} |
/* Allocate a new predicate register. |
*/ |
struct ureg_dst |
ureg_DECL_predicate(struct ureg_program *ureg) |
{ |
if (ureg->nr_preds < UREG_MAX_PRED) { |
return ureg_dst_register(TGSI_FILE_PREDICATE, ureg->nr_preds++); |
} |
assert(0); |
return ureg_dst_register(TGSI_FILE_PREDICATE, 0); |
} |
/* Allocate a new sampler. |
*/ |
struct ureg_src ureg_DECL_sampler( struct ureg_program *ureg, |
unsigned nr ) |
{ |
unsigned i; |
for (i = 0; i < ureg->nr_samplers; i++) |
if (ureg->sampler[i].Index == nr) |
return ureg->sampler[i]; |
if (i < PIPE_MAX_SAMPLERS) { |
ureg->sampler[i] = ureg_src_register( TGSI_FILE_SAMPLER, nr ); |
ureg->nr_samplers++; |
return ureg->sampler[i]; |
} |
assert( 0 ); |
return ureg->sampler[0]; |
} |
/* |
* Allocate a new shader sampler view. |
*/ |
struct ureg_src |
ureg_DECL_sampler_view(struct ureg_program *ureg, |
unsigned index, |
unsigned target, |
unsigned return_type_x, |
unsigned return_type_y, |
unsigned return_type_z, |
unsigned return_type_w) |
{ |
struct ureg_src reg = ureg_src_register(TGSI_FILE_SAMPLER_VIEW, index); |
uint i; |
for (i = 0; i < ureg->nr_sampler_views; i++) { |
if (ureg->sampler_view[i].index == index) { |
return reg; |
} |
} |
if (i < PIPE_MAX_SHADER_SAMPLER_VIEWS) { |
ureg->sampler_view[i].index = index; |
ureg->sampler_view[i].target = target; |
ureg->sampler_view[i].return_type_x = return_type_x; |
ureg->sampler_view[i].return_type_y = return_type_y; |
ureg->sampler_view[i].return_type_z = return_type_z; |
ureg->sampler_view[i].return_type_w = return_type_w; |
ureg->nr_sampler_views++; |
return reg; |
} |
assert(0); |
return reg; |
} |
static int |
match_or_expand_immediate( const unsigned *v, |
unsigned nr, |
unsigned *v2, |
unsigned *pnr2, |
unsigned *swizzle ) |
{ |
unsigned nr2 = *pnr2; |
unsigned i, j; |
*swizzle = 0; |
for (i = 0; i < nr; i++) { |
boolean found = FALSE; |
for (j = 0; j < nr2 && !found; j++) { |
if (v[i] == v2[j]) { |
*swizzle |= j << (i * 2); |
found = TRUE; |
} |
} |
if (!found) { |
if (nr2 >= 4) { |
return FALSE; |
} |
v2[nr2] = v[i]; |
*swizzle |= nr2 << (i * 2); |
nr2++; |
} |
} |
/* Actually expand immediate only when fully succeeded. |
*/ |
*pnr2 = nr2; |
return TRUE; |
} |
static struct ureg_src |
decl_immediate( struct ureg_program *ureg, |
const unsigned *v, |
unsigned nr, |
unsigned type ) |
{ |
unsigned i, j; |
unsigned swizzle = 0; |
/* Could do a first pass where we examine all existing immediates |
* without expanding. |
*/ |
for (i = 0; i < ureg->nr_immediates; i++) { |
if (ureg->immediate[i].type != type) { |
continue; |
} |
if (match_or_expand_immediate(v, |
nr, |
ureg->immediate[i].value.u, |
&ureg->immediate[i].nr, |
&swizzle)) { |
goto out; |
} |
} |
if (ureg->nr_immediates < UREG_MAX_IMMEDIATE) { |
i = ureg->nr_immediates++; |
ureg->immediate[i].type = type; |
if (match_or_expand_immediate(v, |
nr, |
ureg->immediate[i].value.u, |
&ureg->immediate[i].nr, |
&swizzle)) { |
goto out; |
} |
} |
set_bad(ureg); |
out: |
/* Make sure that all referenced elements are from this immediate. |
* Has the effect of making size-one immediates into scalars. |
*/ |
for (j = nr; j < 4; j++) { |
swizzle |= (swizzle & 0x3) << (j * 2); |
} |
return ureg_swizzle(ureg_src_register(TGSI_FILE_IMMEDIATE, i), |
(swizzle >> 0) & 0x3, |
(swizzle >> 2) & 0x3, |
(swizzle >> 4) & 0x3, |
(swizzle >> 6) & 0x3); |
} |
struct ureg_src |
ureg_DECL_immediate( struct ureg_program *ureg, |
const float *v, |
unsigned nr ) |
{ |
union { |
float f[4]; |
unsigned u[4]; |
} fu; |
unsigned int i; |
for (i = 0; i < nr; i++) { |
fu.f[i] = v[i]; |
} |
return decl_immediate(ureg, fu.u, nr, TGSI_IMM_FLOAT32); |
} |
struct ureg_src |
ureg_DECL_immediate_uint( struct ureg_program *ureg, |
const unsigned *v, |
unsigned nr ) |
{ |
return decl_immediate(ureg, v, nr, TGSI_IMM_UINT32); |
} |
struct ureg_src |
ureg_DECL_immediate_block_uint( struct ureg_program *ureg, |
const unsigned *v, |
unsigned nr ) |
{ |
uint index; |
uint i; |
if (ureg->nr_immediates + (nr + 3) / 4 > UREG_MAX_IMMEDIATE) { |
set_bad(ureg); |
return ureg_src_register(TGSI_FILE_IMMEDIATE, 0); |
} |
index = ureg->nr_immediates; |
ureg->nr_immediates += (nr + 3) / 4; |
for (i = index; i < ureg->nr_immediates; i++) { |
ureg->immediate[i].type = TGSI_IMM_UINT32; |
ureg->immediate[i].nr = nr > 4 ? 4 : nr; |
memcpy(ureg->immediate[i].value.u, |
&v[(i - index) * 4], |
ureg->immediate[i].nr * sizeof(uint)); |
nr -= 4; |
} |
return ureg_src_register(TGSI_FILE_IMMEDIATE, index); |
} |
struct ureg_src |
ureg_DECL_immediate_int( struct ureg_program *ureg, |
const int *v, |
unsigned nr ) |
{ |
return decl_immediate(ureg, (const unsigned *)v, nr, TGSI_IMM_INT32); |
} |
void |
ureg_emit_src( struct ureg_program *ureg, |
struct ureg_src src ) |
{ |
unsigned size = 1 + (src.Indirect ? 1 : 0) + |
(src.Dimension ? (src.DimIndirect ? 2 : 1) : 0); |
union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); |
unsigned n = 0; |
assert(src.File != TGSI_FILE_NULL); |
assert(src.File < TGSI_FILE_COUNT); |
out[n].value = 0; |
out[n].src.File = src.File; |
out[n].src.SwizzleX = src.SwizzleX; |
out[n].src.SwizzleY = src.SwizzleY; |
out[n].src.SwizzleZ = src.SwizzleZ; |
out[n].src.SwizzleW = src.SwizzleW; |
out[n].src.Index = src.Index; |
out[n].src.Negate = src.Negate; |
out[0].src.Absolute = src.Absolute; |
n++; |
if (src.Indirect) { |
out[0].src.Indirect = 1; |
out[n].value = 0; |
out[n].ind.File = src.IndirectFile; |
out[n].ind.Swizzle = src.IndirectSwizzle; |
out[n].ind.Index = src.IndirectIndex; |
out[n].ind.ArrayID = src.ArrayID; |
n++; |
} |
if (src.Dimension) { |
out[0].src.Dimension = 1; |
out[n].dim.Dimension = 0; |
out[n].dim.Padding = 0; |
if (src.DimIndirect) { |
out[n].dim.Indirect = 1; |
out[n].dim.Index = src.DimensionIndex; |
n++; |
out[n].value = 0; |
out[n].ind.File = src.DimIndFile; |
out[n].ind.Swizzle = src.DimIndSwizzle; |
out[n].ind.Index = src.DimIndIndex; |
out[n].ind.ArrayID = src.ArrayID; |
} else { |
out[n].dim.Indirect = 0; |
out[n].dim.Index = src.DimensionIndex; |
} |
n++; |
} |
assert(n == size); |
} |
void |
ureg_emit_dst( struct ureg_program *ureg, |
struct ureg_dst dst ) |
{ |
unsigned size = (1 + |
(dst.Indirect ? 1 : 0)); |
union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); |
unsigned n = 0; |
assert(dst.File != TGSI_FILE_NULL); |
assert(dst.File != TGSI_FILE_CONSTANT); |
assert(dst.File != TGSI_FILE_INPUT); |
assert(dst.File != TGSI_FILE_SAMPLER); |
assert(dst.File != TGSI_FILE_SAMPLER_VIEW); |
assert(dst.File != TGSI_FILE_IMMEDIATE); |
assert(dst.File < TGSI_FILE_COUNT); |
out[n].value = 0; |
out[n].dst.File = dst.File; |
out[n].dst.WriteMask = dst.WriteMask; |
out[n].dst.Indirect = dst.Indirect; |
out[n].dst.Index = dst.Index; |
n++; |
if (dst.Indirect) { |
out[n].value = 0; |
out[n].ind.File = dst.IndirectFile; |
out[n].ind.Swizzle = dst.IndirectSwizzle; |
out[n].ind.Index = dst.IndirectIndex; |
out[n].ind.ArrayID = dst.ArrayID; |
n++; |
} |
assert(n == size); |
} |
static void validate( unsigned opcode, |
unsigned nr_dst, |
unsigned nr_src ) |
{ |
#ifdef DEBUG |
const struct tgsi_opcode_info *info = tgsi_get_opcode_info( opcode ); |
assert(info); |
if(info) { |
assert(nr_dst == info->num_dst); |
assert(nr_src == info->num_src); |
} |
#endif |
} |
struct ureg_emit_insn_result |
ureg_emit_insn(struct ureg_program *ureg, |
unsigned opcode, |
boolean saturate, |
boolean predicate, |
boolean pred_negate, |
unsigned pred_swizzle_x, |
unsigned pred_swizzle_y, |
unsigned pred_swizzle_z, |
unsigned pred_swizzle_w, |
unsigned num_dst, |
unsigned num_src ) |
{ |
union tgsi_any_token *out; |
uint count = predicate ? 2 : 1; |
struct ureg_emit_insn_result result; |
validate( opcode, num_dst, num_src ); |
out = get_tokens( ureg, DOMAIN_INSN, count ); |
out[0].insn = tgsi_default_instruction(); |
out[0].insn.Opcode = opcode; |
out[0].insn.Saturate = saturate; |
out[0].insn.NumDstRegs = num_dst; |
out[0].insn.NumSrcRegs = num_src; |
result.insn_token = ureg->domain[DOMAIN_INSN].count - count; |
result.extended_token = result.insn_token; |
if (predicate) { |
out[0].insn.Predicate = 1; |
out[1].insn_predicate = tgsi_default_instruction_predicate(); |
out[1].insn_predicate.Negate = pred_negate; |
out[1].insn_predicate.SwizzleX = pred_swizzle_x; |
out[1].insn_predicate.SwizzleY = pred_swizzle_y; |
out[1].insn_predicate.SwizzleZ = pred_swizzle_z; |
out[1].insn_predicate.SwizzleW = pred_swizzle_w; |
} |
ureg->nr_instructions++; |
return result; |
} |
void |
ureg_emit_label(struct ureg_program *ureg, |
unsigned extended_token, |
unsigned *label_token ) |
{ |
union tgsi_any_token *out, *insn; |
if(!label_token) |
return; |
out = get_tokens( ureg, DOMAIN_INSN, 1 ); |
out[0].value = 0; |
insn = retrieve_token( ureg, DOMAIN_INSN, extended_token ); |
insn->insn.Label = 1; |
*label_token = ureg->domain[DOMAIN_INSN].count - 1; |
} |
/* Will return a number which can be used in a label to point to the |
* next instruction to be emitted. |
*/ |
unsigned |
ureg_get_instruction_number( struct ureg_program *ureg ) |
{ |
return ureg->nr_instructions; |
} |
/* Patch a given label (expressed as a token number) to point to a |
* given instruction (expressed as an instruction number). |
*/ |
void |
ureg_fixup_label(struct ureg_program *ureg, |
unsigned label_token, |
unsigned instruction_number ) |
{ |
union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, label_token ); |
out->insn_label.Label = instruction_number; |
} |
void |
ureg_emit_texture(struct ureg_program *ureg, |
unsigned extended_token, |
unsigned target, unsigned num_offsets) |
{ |
union tgsi_any_token *out, *insn; |
out = get_tokens( ureg, DOMAIN_INSN, 1 ); |
insn = retrieve_token( ureg, DOMAIN_INSN, extended_token ); |
insn->insn.Texture = 1; |
out[0].value = 0; |
out[0].insn_texture.Texture = target; |
out[0].insn_texture.NumOffsets = num_offsets; |
} |
void |
ureg_emit_texture_offset(struct ureg_program *ureg, |
const struct tgsi_texture_offset *offset) |
{ |
union tgsi_any_token *out; |
out = get_tokens( ureg, DOMAIN_INSN, 1); |
out[0].value = 0; |
out[0].insn_texture_offset = *offset; |
} |
void |
ureg_fixup_insn_size(struct ureg_program *ureg, |
unsigned insn ) |
{ |
union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, insn ); |
assert(out->insn.Type == TGSI_TOKEN_TYPE_INSTRUCTION); |
out->insn.NrTokens = ureg->domain[DOMAIN_INSN].count - insn - 1; |
} |
void |
ureg_insn(struct ureg_program *ureg, |
unsigned opcode, |
const struct ureg_dst *dst, |
unsigned nr_dst, |
const struct ureg_src *src, |
unsigned nr_src ) |
{ |
struct ureg_emit_insn_result insn; |
unsigned i; |
boolean saturate; |
boolean predicate; |
boolean negate = FALSE; |
unsigned swizzle[4] = { 0 }; |
saturate = nr_dst ? dst[0].Saturate : FALSE; |
predicate = nr_dst ? dst[0].Predicate : FALSE; |
if (predicate) { |
negate = dst[0].PredNegate; |
swizzle[0] = dst[0].PredSwizzleX; |
swizzle[1] = dst[0].PredSwizzleY; |
swizzle[2] = dst[0].PredSwizzleZ; |
swizzle[3] = dst[0].PredSwizzleW; |
} |
insn = ureg_emit_insn(ureg, |
opcode, |
saturate, |
predicate, |
negate, |
swizzle[0], |
swizzle[1], |
swizzle[2], |
swizzle[3], |
nr_dst, |
nr_src); |
for (i = 0; i < nr_dst; i++) |
ureg_emit_dst( ureg, dst[i] ); |
for (i = 0; i < nr_src; i++) |
ureg_emit_src( ureg, src[i] ); |
ureg_fixup_insn_size( ureg, insn.insn_token ); |
} |
void |
ureg_tex_insn(struct ureg_program *ureg, |
unsigned opcode, |
const struct ureg_dst *dst, |
unsigned nr_dst, |
unsigned target, |
const struct tgsi_texture_offset *texoffsets, |
unsigned nr_offset, |
const struct ureg_src *src, |
unsigned nr_src ) |
{ |
struct ureg_emit_insn_result insn; |
unsigned i; |
boolean saturate; |
boolean predicate; |
boolean negate = FALSE; |
unsigned swizzle[4] = { 0 }; |
saturate = nr_dst ? dst[0].Saturate : FALSE; |
predicate = nr_dst ? dst[0].Predicate : FALSE; |
if (predicate) { |
negate = dst[0].PredNegate; |
swizzle[0] = dst[0].PredSwizzleX; |
swizzle[1] = dst[0].PredSwizzleY; |
swizzle[2] = dst[0].PredSwizzleZ; |
swizzle[3] = dst[0].PredSwizzleW; |
} |
insn = ureg_emit_insn(ureg, |
opcode, |
saturate, |
predicate, |
negate, |
swizzle[0], |
swizzle[1], |
swizzle[2], |
swizzle[3], |
nr_dst, |
nr_src); |
ureg_emit_texture( ureg, insn.extended_token, target, nr_offset ); |
for (i = 0; i < nr_offset; i++) |
ureg_emit_texture_offset( ureg, &texoffsets[i]); |
for (i = 0; i < nr_dst; i++) |
ureg_emit_dst( ureg, dst[i] ); |
for (i = 0; i < nr_src; i++) |
ureg_emit_src( ureg, src[i] ); |
ureg_fixup_insn_size( ureg, insn.insn_token ); |
} |
void |
ureg_label_insn(struct ureg_program *ureg, |
unsigned opcode, |
const struct ureg_src *src, |
unsigned nr_src, |
unsigned *label_token ) |
{ |
struct ureg_emit_insn_result insn; |
unsigned i; |
insn = ureg_emit_insn(ureg, |
opcode, |
FALSE, |
FALSE, |
FALSE, |
TGSI_SWIZZLE_X, |
TGSI_SWIZZLE_Y, |
TGSI_SWIZZLE_Z, |
TGSI_SWIZZLE_W, |
0, |
nr_src); |
ureg_emit_label( ureg, insn.extended_token, label_token ); |
for (i = 0; i < nr_src; i++) |
ureg_emit_src( ureg, src[i] ); |
ureg_fixup_insn_size( ureg, insn.insn_token ); |
} |
static void |
emit_decl_semantic(struct ureg_program *ureg, |
unsigned file, |
unsigned index, |
unsigned semantic_name, |
unsigned semantic_index, |
unsigned usage_mask) |
{ |
union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, 3); |
out[0].value = 0; |
out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; |
out[0].decl.NrTokens = 3; |
out[0].decl.File = file; |
out[0].decl.UsageMask = usage_mask; |
out[0].decl.Semantic = 1; |
out[1].value = 0; |
out[1].decl_range.First = index; |
out[1].decl_range.Last = index; |
out[2].value = 0; |
out[2].decl_semantic.Name = semantic_name; |
out[2].decl_semantic.Index = semantic_index; |
} |
static void |
emit_decl_fs(struct ureg_program *ureg, |
unsigned file, |
unsigned index, |
unsigned semantic_name, |
unsigned semantic_index, |
unsigned interpolate, |
unsigned cylindrical_wrap, |
unsigned centroid) |
{ |
union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, 4); |
out[0].value = 0; |
out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; |
out[0].decl.NrTokens = 4; |
out[0].decl.File = file; |
out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */ |
out[0].decl.Interpolate = 1; |
out[0].decl.Semantic = 1; |
out[1].value = 0; |
out[1].decl_range.First = index; |
out[1].decl_range.Last = index; |
out[2].value = 0; |
out[2].decl_interp.Interpolate = interpolate; |
out[2].decl_interp.CylindricalWrap = cylindrical_wrap; |
out[2].decl_interp.Centroid = centroid; |
out[3].value = 0; |
out[3].decl_semantic.Name = semantic_name; |
out[3].decl_semantic.Index = semantic_index; |
} |
static void |
emit_decl_temps( struct ureg_program *ureg, |
unsigned first, unsigned last, |
boolean local, |
unsigned arrayid ) |
{ |
union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, |
arrayid ? 3 : 2 ); |
out[0].value = 0; |
out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; |
out[0].decl.NrTokens = 2; |
out[0].decl.File = TGSI_FILE_TEMPORARY; |
out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; |
out[0].decl.Local = local; |
out[1].value = 0; |
out[1].decl_range.First = first; |
out[1].decl_range.Last = last; |
if (arrayid) { |
out[0].decl.Array = 1; |
out[2].value = 0; |
out[2].array.ArrayID = arrayid; |
} |
} |
static void emit_decl_range( struct ureg_program *ureg, |
unsigned file, |
unsigned first, |
unsigned count ) |
{ |
union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); |
out[0].value = 0; |
out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; |
out[0].decl.NrTokens = 2; |
out[0].decl.File = file; |
out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; |
out[0].decl.Semantic = 0; |
out[1].value = 0; |
out[1].decl_range.First = first; |
out[1].decl_range.Last = first + count - 1; |
} |
static void |
emit_decl_range2D(struct ureg_program *ureg, |
unsigned file, |
unsigned first, |
unsigned last, |
unsigned index2D) |
{ |
union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, 3); |
out[0].value = 0; |
out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; |
out[0].decl.NrTokens = 3; |
out[0].decl.File = file; |
out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; |
out[0].decl.Dimension = 1; |
out[1].value = 0; |
out[1].decl_range.First = first; |
out[1].decl_range.Last = last; |
out[2].value = 0; |
out[2].decl_dim.Index2D = index2D; |
} |
static void |
emit_decl_sampler_view(struct ureg_program *ureg, |
unsigned index, |
unsigned target, |
unsigned return_type_x, |
unsigned return_type_y, |
unsigned return_type_z, |
unsigned return_type_w ) |
{ |
union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, 3); |
out[0].value = 0; |
out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; |
out[0].decl.NrTokens = 3; |
out[0].decl.File = TGSI_FILE_SAMPLER_VIEW; |
out[0].decl.UsageMask = 0xf; |
out[1].value = 0; |
out[1].decl_range.First = index; |
out[1].decl_range.Last = index; |
out[2].value = 0; |
out[2].decl_sampler_view.Resource = target; |
out[2].decl_sampler_view.ReturnTypeX = return_type_x; |
out[2].decl_sampler_view.ReturnTypeY = return_type_y; |
out[2].decl_sampler_view.ReturnTypeZ = return_type_z; |
out[2].decl_sampler_view.ReturnTypeW = return_type_w; |
} |
static void |
emit_immediate( struct ureg_program *ureg, |
const unsigned *v, |
unsigned type ) |
{ |
union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 5 ); |
out[0].value = 0; |
out[0].imm.Type = TGSI_TOKEN_TYPE_IMMEDIATE; |
out[0].imm.NrTokens = 5; |
out[0].imm.DataType = type; |
out[0].imm.Padding = 0; |
out[1].imm_data.Uint = v[0]; |
out[2].imm_data.Uint = v[1]; |
out[3].imm_data.Uint = v[2]; |
out[4].imm_data.Uint = v[3]; |
} |
static void |
emit_property(struct ureg_program *ureg, |
unsigned name, |
unsigned data) |
{ |
union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, 2); |
out[0].value = 0; |
out[0].prop.Type = TGSI_TOKEN_TYPE_PROPERTY; |
out[0].prop.NrTokens = 2; |
out[0].prop.PropertyName = name; |
out[1].prop_data.Data = data; |
} |
static void emit_decls( struct ureg_program *ureg ) |
{ |
unsigned i; |
if (ureg->property_gs_input_prim != ~0) { |
assert(ureg->processor == TGSI_PROCESSOR_GEOMETRY); |
emit_property(ureg, |
TGSI_PROPERTY_GS_INPUT_PRIM, |
ureg->property_gs_input_prim); |
} |
if (ureg->property_gs_output_prim != ~0) { |
assert(ureg->processor == TGSI_PROCESSOR_GEOMETRY); |
emit_property(ureg, |
TGSI_PROPERTY_GS_OUTPUT_PRIM, |
ureg->property_gs_output_prim); |
} |
if (ureg->property_gs_max_vertices != ~0) { |
assert(ureg->processor == TGSI_PROCESSOR_GEOMETRY); |
emit_property(ureg, |
TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES, |
ureg->property_gs_max_vertices); |
} |
if (ureg->property_fs_coord_origin) { |
assert(ureg->processor == TGSI_PROCESSOR_FRAGMENT); |
emit_property(ureg, |
TGSI_PROPERTY_FS_COORD_ORIGIN, |
ureg->property_fs_coord_origin); |
} |
if (ureg->property_fs_coord_pixel_center) { |
assert(ureg->processor == TGSI_PROCESSOR_FRAGMENT); |
emit_property(ureg, |
TGSI_PROPERTY_FS_COORD_PIXEL_CENTER, |
ureg->property_fs_coord_pixel_center); |
} |
if (ureg->property_fs_color0_writes_all_cbufs) { |
assert(ureg->processor == TGSI_PROCESSOR_FRAGMENT); |
emit_property(ureg, |
TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS, |
ureg->property_fs_color0_writes_all_cbufs); |
} |
if (ureg->property_fs_depth_layout) { |
assert(ureg->processor == TGSI_PROCESSOR_FRAGMENT); |
emit_property(ureg, |
TGSI_PROPERTY_FS_DEPTH_LAYOUT, |
ureg->property_fs_depth_layout); |
} |
if (ureg->processor == TGSI_PROCESSOR_VERTEX) { |
for (i = 0; i < UREG_MAX_INPUT; i++) { |
if (ureg->vs_inputs[i/32] & (1 << (i%32))) { |
emit_decl_range( ureg, TGSI_FILE_INPUT, i, 1 ); |
} |
} |
} else if (ureg->processor == TGSI_PROCESSOR_FRAGMENT) { |
for (i = 0; i < ureg->nr_fs_inputs; i++) { |
emit_decl_fs(ureg, |
TGSI_FILE_INPUT, |
i, |
ureg->fs_input[i].semantic_name, |
ureg->fs_input[i].semantic_index, |
ureg->fs_input[i].interp, |
ureg->fs_input[i].cylindrical_wrap, |
ureg->fs_input[i].centroid); |
} |
} else { |
for (i = 0; i < ureg->nr_gs_inputs; i++) { |
emit_decl_semantic(ureg, |
TGSI_FILE_INPUT, |
ureg->gs_input[i].index, |
ureg->gs_input[i].semantic_name, |
ureg->gs_input[i].semantic_index, |
TGSI_WRITEMASK_XYZW); |
} |
} |
for (i = 0; i < ureg->nr_system_values; i++) { |
emit_decl_semantic(ureg, |
TGSI_FILE_SYSTEM_VALUE, |
ureg->system_value[i].index, |
ureg->system_value[i].semantic_name, |
ureg->system_value[i].semantic_index, |
TGSI_WRITEMASK_XYZW); |
} |
for (i = 0; i < ureg->nr_outputs; i++) { |
emit_decl_semantic(ureg, |
TGSI_FILE_OUTPUT, |
i, |
ureg->output[i].semantic_name, |
ureg->output[i].semantic_index, |
ureg->output[i].usage_mask); |
} |
for (i = 0; i < ureg->nr_samplers; i++) { |
emit_decl_range( ureg, |
TGSI_FILE_SAMPLER, |
ureg->sampler[i].Index, 1 ); |
} |
for (i = 0; i < ureg->nr_sampler_views; i++) { |
emit_decl_sampler_view(ureg, |
ureg->sampler_view[i].index, |
ureg->sampler_view[i].target, |
ureg->sampler_view[i].return_type_x, |
ureg->sampler_view[i].return_type_y, |
ureg->sampler_view[i].return_type_z, |
ureg->sampler_view[i].return_type_w); |
} |
if (ureg->const_decls.nr_constant_ranges) { |
for (i = 0; i < ureg->const_decls.nr_constant_ranges; i++) { |
emit_decl_range(ureg, |
TGSI_FILE_CONSTANT, |
ureg->const_decls.constant_range[i].first, |
ureg->const_decls.constant_range[i].last - ureg->const_decls.constant_range[i].first + 1); |
} |
} |
for (i = 0; i < PIPE_MAX_CONSTANT_BUFFERS; i++) { |
struct const_decl *decl = &ureg->const_decls2D[i]; |
if (decl->nr_constant_ranges) { |
uint j; |
for (j = 0; j < decl->nr_constant_ranges; j++) { |
emit_decl_range2D(ureg, |
TGSI_FILE_CONSTANT, |
decl->constant_range[j].first, |
decl->constant_range[j].last, |
i); |
} |
} |
} |
if (ureg->nr_temps) { |
unsigned array = 0; |
for (i = 0; i < ureg->nr_temps;) { |
boolean local = util_bitmask_get(ureg->local_temps, i); |
unsigned first = i; |
i = util_bitmask_get_next_index(ureg->decl_temps, i + 1); |
if (i == UTIL_BITMASK_INVALID_INDEX) |
i = ureg->nr_temps; |
if (array < ureg->nr_array_temps && ureg->array_temps[array] == first) |
emit_decl_temps( ureg, first, i - 1, local, ++array ); |
else |
emit_decl_temps( ureg, first, i - 1, local, 0 ); |
} |
} |
if (ureg->nr_addrs) { |
emit_decl_range( ureg, |
TGSI_FILE_ADDRESS, |
0, ureg->nr_addrs ); |
} |
if (ureg->nr_preds) { |
emit_decl_range(ureg, |
TGSI_FILE_PREDICATE, |
0, |
ureg->nr_preds); |
} |
for (i = 0; i < ureg->nr_immediates; i++) { |
emit_immediate( ureg, |
ureg->immediate[i].value.u, |
ureg->immediate[i].type ); |
} |
} |
/* Append the instruction tokens onto the declarations to build a |
* contiguous stream suitable to send to the driver. |
*/ |
static void copy_instructions( struct ureg_program *ureg ) |
{ |
unsigned nr_tokens = ureg->domain[DOMAIN_INSN].count; |
union tgsi_any_token *out = get_tokens( ureg, |
DOMAIN_DECL, |
nr_tokens ); |
memcpy(out, |
ureg->domain[DOMAIN_INSN].tokens, |
nr_tokens * sizeof out[0] ); |
} |
static void |
fixup_header_size(struct ureg_program *ureg) |
{ |
union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_DECL, 0 ); |
out->header.BodySize = ureg->domain[DOMAIN_DECL].count - 2; |
} |
static void |
emit_header( struct ureg_program *ureg ) |
{ |
union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); |
out[0].header.HeaderSize = 2; |
out[0].header.BodySize = 0; |
out[1].processor.Processor = ureg->processor; |
out[1].processor.Padding = 0; |
} |
const struct tgsi_token *ureg_finalize( struct ureg_program *ureg ) |
{ |
const struct tgsi_token *tokens; |
emit_header( ureg ); |
emit_decls( ureg ); |
copy_instructions( ureg ); |
fixup_header_size( ureg ); |
if (ureg->domain[0].tokens == error_tokens || |
ureg->domain[1].tokens == error_tokens) { |
debug_printf("%s: error in generated shader\n", __FUNCTION__); |
assert(0); |
return NULL; |
} |
tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; |
if (0) { |
debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__, |
ureg->domain[DOMAIN_DECL].count); |
tgsi_dump( tokens, 0 ); |
} |
#if DEBUG |
if (tokens && !tgsi_sanity_check(tokens)) { |
debug_printf("tgsi_ureg.c, sanity check failed on generated tokens:\n"); |
tgsi_dump(tokens, 0); |
assert(0); |
} |
#endif |
return tokens; |
} |
void *ureg_create_shader( struct ureg_program *ureg, |
struct pipe_context *pipe, |
const struct pipe_stream_output_info *so ) |
{ |
struct pipe_shader_state state; |
state.tokens = ureg_finalize(ureg); |
if(!state.tokens) |
return NULL; |
if (so) |
state.stream_output = *so; |
else |
memset(&state.stream_output, 0, sizeof(state.stream_output)); |
if (ureg->processor == TGSI_PROCESSOR_VERTEX) |
return pipe->create_vs_state( pipe, &state ); |
else |
return pipe->create_fs_state( pipe, &state ); |
} |
const struct tgsi_token *ureg_get_tokens( struct ureg_program *ureg, |
unsigned *nr_tokens ) |
{ |
const struct tgsi_token *tokens; |
ureg_finalize(ureg); |
tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; |
if (nr_tokens) |
*nr_tokens = ureg->domain[DOMAIN_DECL].size; |
ureg->domain[DOMAIN_DECL].tokens = 0; |
ureg->domain[DOMAIN_DECL].size = 0; |
ureg->domain[DOMAIN_DECL].order = 0; |
ureg->domain[DOMAIN_DECL].count = 0; |
return tokens; |
} |
void ureg_free_tokens( const struct tgsi_token *tokens ) |
{ |
FREE((struct tgsi_token *)tokens); |
} |
struct ureg_program *ureg_create( unsigned processor ) |
{ |
struct ureg_program *ureg = CALLOC_STRUCT( ureg_program ); |
if (ureg == NULL) |
goto no_ureg; |
ureg->processor = processor; |
ureg->property_gs_input_prim = ~0; |
ureg->property_gs_output_prim = ~0; |
ureg->property_gs_max_vertices = ~0; |
ureg->free_temps = util_bitmask_create(); |
if (ureg->free_temps == NULL) |
goto no_free_temps; |
ureg->local_temps = util_bitmask_create(); |
if (ureg->local_temps == NULL) |
goto no_local_temps; |
ureg->decl_temps = util_bitmask_create(); |
if (ureg->decl_temps == NULL) |
goto no_decl_temps; |
return ureg; |
no_decl_temps: |
util_bitmask_destroy(ureg->local_temps); |
no_local_temps: |
util_bitmask_destroy(ureg->free_temps); |
no_free_temps: |
FREE(ureg); |
no_ureg: |
return NULL; |
} |
const unsigned |
ureg_get_nr_outputs( const struct ureg_program *ureg ) |
{ |
if (!ureg) |
return 0; |
return ureg->nr_outputs; |
} |
void ureg_destroy( struct ureg_program *ureg ) |
{ |
unsigned i; |
for (i = 0; i < Elements(ureg->domain); i++) { |
if (ureg->domain[i].tokens && |
ureg->domain[i].tokens != error_tokens) |
FREE(ureg->domain[i].tokens); |
} |
util_bitmask_destroy(ureg->free_temps); |
util_bitmask_destroy(ureg->local_temps); |
util_bitmask_destroy(ureg->decl_temps); |
FREE(ureg); |
} |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_ureg.h |
---|
0,0 → 1,1278 |
/************************************************************************** |
* |
* Copyright 2009 VMware, Inc. |
* 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 VMWARE, INC 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. |
* |
**************************************************************************/ |
#ifndef TGSI_UREG_H |
#define TGSI_UREG_H |
#include "pipe/p_compiler.h" |
#include "pipe/p_shader_tokens.h" |
#include "util/u_debug.h" |
#ifdef __cplusplus |
extern "C" { |
#endif |
struct ureg_program; |
struct pipe_stream_output_info; |
/* Almost a tgsi_src_register, but we need to pull in the Absolute |
* flag from the _ext token. Indirect flag always implies ADDR[0]. |
*/ |
struct ureg_src |
{ |
unsigned File : 4; /* TGSI_FILE_ */ |
unsigned SwizzleX : 2; /* TGSI_SWIZZLE_ */ |
unsigned SwizzleY : 2; /* TGSI_SWIZZLE_ */ |
unsigned SwizzleZ : 2; /* TGSI_SWIZZLE_ */ |
unsigned SwizzleW : 2; /* TGSI_SWIZZLE_ */ |
unsigned Indirect : 1; /* BOOL */ |
unsigned DimIndirect : 1; /* BOOL */ |
unsigned Dimension : 1; /* BOOL */ |
unsigned Absolute : 1; /* BOOL */ |
unsigned Negate : 1; /* BOOL */ |
unsigned IndirectFile : 4; /* TGSI_FILE_ */ |
unsigned IndirectSwizzle : 2; /* TGSI_SWIZZLE_ */ |
unsigned DimIndFile : 4; /* TGSI_FILE_ */ |
unsigned DimIndSwizzle : 2; /* TGSI_SWIZZLE_ */ |
int Index : 16; /* SINT */ |
int IndirectIndex : 16; /* SINT */ |
int DimensionIndex : 16; /* SINT */ |
int DimIndIndex : 16; /* SINT */ |
unsigned ArrayID : 10; /* UINT */ |
}; |
/* Very similar to a tgsi_dst_register, removing unsupported fields |
* and adding a Saturate flag. It's easier to push saturate into the |
* destination register than to try and create a _SAT variant of each |
* instruction function. |
*/ |
struct ureg_dst |
{ |
unsigned File : 4; /* TGSI_FILE_ */ |
unsigned WriteMask : 4; /* TGSI_WRITEMASK_ */ |
unsigned Indirect : 1; /* BOOL */ |
unsigned Saturate : 1; /* BOOL */ |
unsigned Predicate : 1; |
unsigned PredNegate : 1; /* BOOL */ |
unsigned PredSwizzleX : 2; /* TGSI_SWIZZLE_ */ |
unsigned PredSwizzleY : 2; /* TGSI_SWIZZLE_ */ |
unsigned PredSwizzleZ : 2; /* TGSI_SWIZZLE_ */ |
unsigned PredSwizzleW : 2; /* TGSI_SWIZZLE_ */ |
int Index : 16; /* SINT */ |
int IndirectIndex : 16; /* SINT */ |
unsigned IndirectFile : 4; /* TGSI_FILE_ */ |
int IndirectSwizzle : 2; /* TGSI_SWIZZLE_ */ |
unsigned ArrayID : 10; /* UINT */ |
}; |
struct pipe_context; |
struct ureg_program * |
ureg_create( unsigned processor ); |
const struct tgsi_token * |
ureg_finalize( struct ureg_program * ); |
/* Create and return a shader: |
*/ |
void * |
ureg_create_shader( struct ureg_program *, |
struct pipe_context *pipe, |
const struct pipe_stream_output_info *so ); |
/* Alternately, return the built token stream and hand ownership of |
* that memory to the caller: |
*/ |
const struct tgsi_token * |
ureg_get_tokens( struct ureg_program *ureg, |
unsigned *nr_tokens ); |
/* |
* Returns the number of currently declared outputs. |
*/ |
const unsigned |
ureg_get_nr_outputs( const struct ureg_program *ureg ); |
/* Free the tokens created by ureg_get_tokens() */ |
void ureg_free_tokens( const struct tgsi_token *tokens ); |
void |
ureg_destroy( struct ureg_program * ); |
/*********************************************************************** |
* Convenience routine: |
*/ |
static INLINE void * |
ureg_create_shader_with_so_and_destroy( struct ureg_program *p, |
struct pipe_context *pipe, |
const struct pipe_stream_output_info *so ) |
{ |
void *result = ureg_create_shader( p, pipe, so ); |
ureg_destroy( p ); |
return result; |
} |
static INLINE void * |
ureg_create_shader_and_destroy( struct ureg_program *p, |
struct pipe_context *pipe ) |
{ |
return ureg_create_shader_with_so_and_destroy(p, pipe, NULL); |
} |
/*********************************************************************** |
* Build shader properties: |
*/ |
void |
ureg_property_gs_input_prim(struct ureg_program *ureg, |
unsigned input_prim); |
void |
ureg_property_gs_output_prim(struct ureg_program *ureg, |
unsigned output_prim); |
void |
ureg_property_gs_max_vertices(struct ureg_program *ureg, |
unsigned max_vertices); |
void |
ureg_property_fs_coord_origin(struct ureg_program *ureg, |
unsigned fs_coord_origin); |
void |
ureg_property_fs_coord_pixel_center(struct ureg_program *ureg, |
unsigned fs_coord_pixel_center); |
void |
ureg_property_fs_color0_writes_all_cbufs(struct ureg_program *ureg, |
unsigned fs_color0_writes_all_cbufs); |
void |
ureg_property_fs_depth_layout(struct ureg_program *ureg, |
unsigned fs_depth_layout); |
/*********************************************************************** |
* Build shader declarations: |
*/ |
struct ureg_src |
ureg_DECL_fs_input_cyl_centroid(struct ureg_program *, |
unsigned semantic_name, |
unsigned semantic_index, |
unsigned interp_mode, |
unsigned cylindrical_wrap, |
unsigned centroid); |
static INLINE struct ureg_src |
ureg_DECL_fs_input_cyl(struct ureg_program *ureg, |
unsigned semantic_name, |
unsigned semantic_index, |
unsigned interp_mode, |
unsigned cylindrical_wrap) |
{ |
return ureg_DECL_fs_input_cyl_centroid(ureg, |
semantic_name, |
semantic_index, |
interp_mode, |
cylindrical_wrap, |
0); |
} |
static INLINE struct ureg_src |
ureg_DECL_fs_input(struct ureg_program *ureg, |
unsigned semantic_name, |
unsigned semantic_index, |
unsigned interp_mode) |
{ |
return ureg_DECL_fs_input_cyl_centroid(ureg, |
semantic_name, |
semantic_index, |
interp_mode, |
0, 0); |
} |
struct ureg_src |
ureg_DECL_vs_input( struct ureg_program *, |
unsigned index ); |
struct ureg_src |
ureg_DECL_gs_input(struct ureg_program *, |
unsigned index, |
unsigned semantic_name, |
unsigned semantic_index); |
struct ureg_src |
ureg_DECL_system_value(struct ureg_program *, |
unsigned index, |
unsigned semantic_name, |
unsigned semantic_index); |
struct ureg_dst |
ureg_DECL_output_masked( struct ureg_program *, |
unsigned semantic_name, |
unsigned semantic_index, |
unsigned usage_mask ); |
struct ureg_dst |
ureg_DECL_output( struct ureg_program *, |
unsigned semantic_name, |
unsigned semantic_index ); |
struct ureg_src |
ureg_DECL_immediate( struct ureg_program *, |
const float *v, |
unsigned nr ); |
struct ureg_src |
ureg_DECL_immediate_uint( struct ureg_program *, |
const unsigned *v, |
unsigned nr ); |
struct ureg_src |
ureg_DECL_immediate_block_uint( struct ureg_program *, |
const unsigned *v, |
unsigned nr ); |
struct ureg_src |
ureg_DECL_immediate_int( struct ureg_program *, |
const int *v, |
unsigned nr ); |
void |
ureg_DECL_constant2D(struct ureg_program *ureg, |
unsigned first, |
unsigned last, |
unsigned index2D); |
struct ureg_src |
ureg_DECL_constant( struct ureg_program *, |
unsigned index ); |
struct ureg_dst |
ureg_DECL_temporary( struct ureg_program * ); |
/** |
* Emit a temporary with the LOCAL declaration flag set. For use when |
* the register value is not required to be preserved across |
* subroutine boundaries. |
*/ |
struct ureg_dst |
ureg_DECL_local_temporary( struct ureg_program * ); |
/** |
* Declare "size" continuous temporary registers. |
*/ |
struct ureg_dst |
ureg_DECL_array_temporary( struct ureg_program *, |
unsigned size, |
boolean local ); |
void |
ureg_release_temporary( struct ureg_program *ureg, |
struct ureg_dst tmp ); |
struct ureg_dst |
ureg_DECL_address( struct ureg_program * ); |
struct ureg_dst |
ureg_DECL_predicate(struct ureg_program *); |
/* Supply an index to the sampler declaration as this is the hook to |
* the external pipe_sampler state. Users of this function probably |
* don't want just any sampler, but a specific one which they've set |
* up state for in the context. |
*/ |
struct ureg_src |
ureg_DECL_sampler( struct ureg_program *, |
unsigned index ); |
struct ureg_src |
ureg_DECL_sampler_view(struct ureg_program *, |
unsigned index, |
unsigned target, |
unsigned return_type_x, |
unsigned return_type_y, |
unsigned return_type_z, |
unsigned return_type_w ); |
static INLINE struct ureg_src |
ureg_imm4f( struct ureg_program *ureg, |
float a, float b, |
float c, float d) |
{ |
float v[4]; |
v[0] = a; |
v[1] = b; |
v[2] = c; |
v[3] = d; |
return ureg_DECL_immediate( ureg, v, 4 ); |
} |
static INLINE struct ureg_src |
ureg_imm3f( struct ureg_program *ureg, |
float a, float b, |
float c) |
{ |
float v[3]; |
v[0] = a; |
v[1] = b; |
v[2] = c; |
return ureg_DECL_immediate( ureg, v, 3 ); |
} |
static INLINE struct ureg_src |
ureg_imm2f( struct ureg_program *ureg, |
float a, float b) |
{ |
float v[2]; |
v[0] = a; |
v[1] = b; |
return ureg_DECL_immediate( ureg, v, 2 ); |
} |
static INLINE struct ureg_src |
ureg_imm1f( struct ureg_program *ureg, |
float a) |
{ |
float v[1]; |
v[0] = a; |
return ureg_DECL_immediate( ureg, v, 1 ); |
} |
static INLINE struct ureg_src |
ureg_imm4u( struct ureg_program *ureg, |
unsigned a, unsigned b, |
unsigned c, unsigned d) |
{ |
unsigned v[4]; |
v[0] = a; |
v[1] = b; |
v[2] = c; |
v[3] = d; |
return ureg_DECL_immediate_uint( ureg, v, 4 ); |
} |
static INLINE struct ureg_src |
ureg_imm3u( struct ureg_program *ureg, |
unsigned a, unsigned b, |
unsigned c) |
{ |
unsigned v[3]; |
v[0] = a; |
v[1] = b; |
v[2] = c; |
return ureg_DECL_immediate_uint( ureg, v, 3 ); |
} |
static INLINE struct ureg_src |
ureg_imm2u( struct ureg_program *ureg, |
unsigned a, unsigned b) |
{ |
unsigned v[2]; |
v[0] = a; |
v[1] = b; |
return ureg_DECL_immediate_uint( ureg, v, 2 ); |
} |
static INLINE struct ureg_src |
ureg_imm1u( struct ureg_program *ureg, |
unsigned a) |
{ |
return ureg_DECL_immediate_uint( ureg, &a, 1 ); |
} |
static INLINE struct ureg_src |
ureg_imm4i( struct ureg_program *ureg, |
int a, int b, |
int c, int d) |
{ |
int v[4]; |
v[0] = a; |
v[1] = b; |
v[2] = c; |
v[3] = d; |
return ureg_DECL_immediate_int( ureg, v, 4 ); |
} |
static INLINE struct ureg_src |
ureg_imm3i( struct ureg_program *ureg, |
int a, int b, |
int c) |
{ |
int v[3]; |
v[0] = a; |
v[1] = b; |
v[2] = c; |
return ureg_DECL_immediate_int( ureg, v, 3 ); |
} |
static INLINE struct ureg_src |
ureg_imm2i( struct ureg_program *ureg, |
int a, int b) |
{ |
int v[2]; |
v[0] = a; |
v[1] = b; |
return ureg_DECL_immediate_int( ureg, v, 2 ); |
} |
static INLINE struct ureg_src |
ureg_imm1i( struct ureg_program *ureg, |
int a) |
{ |
return ureg_DECL_immediate_int( ureg, &a, 1 ); |
} |
/*********************************************************************** |
* Functions for patching up labels |
*/ |
/* Will return a number which can be used in a label to point to the |
* next instruction to be emitted. |
*/ |
unsigned |
ureg_get_instruction_number( struct ureg_program *ureg ); |
/* Patch a given label (expressed as a token number) to point to a |
* given instruction (expressed as an instruction number). |
* |
* Labels are obtained from instruction emitters, eg ureg_CAL(). |
* Instruction numbers are obtained from ureg_get_instruction_number(), |
* above. |
*/ |
void |
ureg_fixup_label(struct ureg_program *ureg, |
unsigned label_token, |
unsigned instruction_number ); |
/* Generic instruction emitter. Use if you need to pass the opcode as |
* a parameter, rather than using the emit_OP() variants below. |
*/ |
void |
ureg_insn(struct ureg_program *ureg, |
unsigned opcode, |
const struct ureg_dst *dst, |
unsigned nr_dst, |
const struct ureg_src *src, |
unsigned nr_src ); |
void |
ureg_tex_insn(struct ureg_program *ureg, |
unsigned opcode, |
const struct ureg_dst *dst, |
unsigned nr_dst, |
unsigned target, |
const struct tgsi_texture_offset *texoffsets, |
unsigned nr_offset, |
const struct ureg_src *src, |
unsigned nr_src ); |
void |
ureg_label_insn(struct ureg_program *ureg, |
unsigned opcode, |
const struct ureg_src *src, |
unsigned nr_src, |
unsigned *label); |
/*********************************************************************** |
* Internal instruction helpers, don't call these directly: |
*/ |
struct ureg_emit_insn_result { |
unsigned insn_token; /*< Used to fixup insn size. */ |
unsigned extended_token; /*< Used to set the Extended bit, usually the same as insn_token. */ |
}; |
struct ureg_emit_insn_result |
ureg_emit_insn(struct ureg_program *ureg, |
unsigned opcode, |
boolean saturate, |
boolean predicate, |
boolean pred_negate, |
unsigned pred_swizzle_x, |
unsigned pred_swizzle_y, |
unsigned pred_swizzle_z, |
unsigned pred_swizzle_w, |
unsigned num_dst, |
unsigned num_src ); |
void |
ureg_emit_label(struct ureg_program *ureg, |
unsigned insn_token, |
unsigned *label_token ); |
void |
ureg_emit_texture(struct ureg_program *ureg, |
unsigned insn_token, |
unsigned target, unsigned num_offsets); |
void |
ureg_emit_texture_offset(struct ureg_program *ureg, |
const struct tgsi_texture_offset *offset); |
void |
ureg_emit_dst( struct ureg_program *ureg, |
struct ureg_dst dst ); |
void |
ureg_emit_src( struct ureg_program *ureg, |
struct ureg_src src ); |
void |
ureg_fixup_insn_size(struct ureg_program *ureg, |
unsigned insn ); |
#define OP00( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
unsigned insn = ureg_emit_insn(ureg, \ |
opcode, \ |
FALSE, \ |
FALSE, \ |
FALSE, \ |
TGSI_SWIZZLE_X, \ |
TGSI_SWIZZLE_Y, \ |
TGSI_SWIZZLE_Z, \ |
TGSI_SWIZZLE_W, \ |
0, \ |
0).insn_token; \ |
ureg_fixup_insn_size( ureg, insn ); \ |
} |
#define OP01( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_src src ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
unsigned insn = ureg_emit_insn(ureg, \ |
opcode, \ |
FALSE, \ |
FALSE, \ |
FALSE, \ |
TGSI_SWIZZLE_X, \ |
TGSI_SWIZZLE_Y, \ |
TGSI_SWIZZLE_Z, \ |
TGSI_SWIZZLE_W, \ |
0, \ |
1).insn_token; \ |
ureg_emit_src( ureg, src ); \ |
ureg_fixup_insn_size( ureg, insn ); \ |
} |
#define OP00_LBL( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
unsigned *label_token ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
struct ureg_emit_insn_result insn; \ |
insn = ureg_emit_insn(ureg, \ |
opcode, \ |
FALSE, \ |
FALSE, \ |
FALSE, \ |
TGSI_SWIZZLE_X, \ |
TGSI_SWIZZLE_Y, \ |
TGSI_SWIZZLE_Z, \ |
TGSI_SWIZZLE_W, \ |
0, \ |
0); \ |
ureg_emit_label( ureg, insn.extended_token, label_token ); \ |
ureg_fixup_insn_size( ureg, insn.insn_token ); \ |
} |
#define OP01_LBL( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_src src, \ |
unsigned *label_token ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
struct ureg_emit_insn_result insn; \ |
insn = ureg_emit_insn(ureg, \ |
opcode, \ |
FALSE, \ |
FALSE, \ |
FALSE, \ |
TGSI_SWIZZLE_X, \ |
TGSI_SWIZZLE_Y, \ |
TGSI_SWIZZLE_Z, \ |
TGSI_SWIZZLE_W, \ |
0, \ |
1); \ |
ureg_emit_label( ureg, insn.extended_token, label_token ); \ |
ureg_emit_src( ureg, src ); \ |
ureg_fixup_insn_size( ureg, insn.insn_token ); \ |
} |
#define OP10( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_dst dst ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
unsigned insn = ureg_emit_insn(ureg, \ |
opcode, \ |
dst.Saturate, \ |
dst.Predicate, \ |
dst.PredNegate, \ |
dst.PredSwizzleX, \ |
dst.PredSwizzleY, \ |
dst.PredSwizzleZ, \ |
dst.PredSwizzleW, \ |
1, \ |
0).insn_token; \ |
ureg_emit_dst( ureg, dst ); \ |
ureg_fixup_insn_size( ureg, insn ); \ |
} |
#define OP11( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_dst dst, \ |
struct ureg_src src ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
unsigned insn = ureg_emit_insn(ureg, \ |
opcode, \ |
dst.Saturate, \ |
dst.Predicate, \ |
dst.PredNegate, \ |
dst.PredSwizzleX, \ |
dst.PredSwizzleY, \ |
dst.PredSwizzleZ, \ |
dst.PredSwizzleW, \ |
1, \ |
1).insn_token; \ |
ureg_emit_dst( ureg, dst ); \ |
ureg_emit_src( ureg, src ); \ |
ureg_fixup_insn_size( ureg, insn ); \ |
} |
#define OP12( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_dst dst, \ |
struct ureg_src src0, \ |
struct ureg_src src1 ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
unsigned insn = ureg_emit_insn(ureg, \ |
opcode, \ |
dst.Saturate, \ |
dst.Predicate, \ |
dst.PredNegate, \ |
dst.PredSwizzleX, \ |
dst.PredSwizzleY, \ |
dst.PredSwizzleZ, \ |
dst.PredSwizzleW, \ |
1, \ |
2).insn_token; \ |
ureg_emit_dst( ureg, dst ); \ |
ureg_emit_src( ureg, src0 ); \ |
ureg_emit_src( ureg, src1 ); \ |
ureg_fixup_insn_size( ureg, insn ); \ |
} |
#define OP12_TEX( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_dst dst, \ |
unsigned target, \ |
struct ureg_src src0, \ |
struct ureg_src src1 ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
struct ureg_emit_insn_result insn; \ |
insn = ureg_emit_insn(ureg, \ |
opcode, \ |
dst.Saturate, \ |
dst.Predicate, \ |
dst.PredNegate, \ |
dst.PredSwizzleX, \ |
dst.PredSwizzleY, \ |
dst.PredSwizzleZ, \ |
dst.PredSwizzleW, \ |
1, \ |
2); \ |
ureg_emit_texture( ureg, insn.extended_token, target, 0 ); \ |
ureg_emit_dst( ureg, dst ); \ |
ureg_emit_src( ureg, src0 ); \ |
ureg_emit_src( ureg, src1 ); \ |
ureg_fixup_insn_size( ureg, insn.insn_token ); \ |
} |
#define OP12_SAMPLE( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_dst dst, \ |
struct ureg_src src0, \ |
struct ureg_src src1 ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
unsigned target = TGSI_TEXTURE_UNKNOWN; \ |
struct ureg_emit_insn_result insn; \ |
insn = ureg_emit_insn(ureg, \ |
opcode, \ |
dst.Saturate, \ |
dst.Predicate, \ |
dst.PredNegate, \ |
dst.PredSwizzleX, \ |
dst.PredSwizzleY, \ |
dst.PredSwizzleZ, \ |
dst.PredSwizzleW, \ |
1, \ |
2); \ |
ureg_emit_texture( ureg, insn.extended_token, target, 0 ); \ |
ureg_emit_dst( ureg, dst ); \ |
ureg_emit_src( ureg, src0 ); \ |
ureg_emit_src( ureg, src1 ); \ |
ureg_fixup_insn_size( ureg, insn.insn_token ); \ |
} |
#define OP13( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_dst dst, \ |
struct ureg_src src0, \ |
struct ureg_src src1, \ |
struct ureg_src src2 ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
unsigned insn = ureg_emit_insn(ureg, \ |
opcode, \ |
dst.Saturate, \ |
dst.Predicate, \ |
dst.PredNegate, \ |
dst.PredSwizzleX, \ |
dst.PredSwizzleY, \ |
dst.PredSwizzleZ, \ |
dst.PredSwizzleW, \ |
1, \ |
3).insn_token; \ |
ureg_emit_dst( ureg, dst ); \ |
ureg_emit_src( ureg, src0 ); \ |
ureg_emit_src( ureg, src1 ); \ |
ureg_emit_src( ureg, src2 ); \ |
ureg_fixup_insn_size( ureg, insn ); \ |
} |
#define OP13_SAMPLE( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_dst dst, \ |
struct ureg_src src0, \ |
struct ureg_src src1, \ |
struct ureg_src src2 ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
unsigned target = TGSI_TEXTURE_UNKNOWN; \ |
struct ureg_emit_insn_result insn; \ |
insn = ureg_emit_insn(ureg, \ |
opcode, \ |
dst.Saturate, \ |
dst.Predicate, \ |
dst.PredNegate, \ |
dst.PredSwizzleX, \ |
dst.PredSwizzleY, \ |
dst.PredSwizzleZ, \ |
dst.PredSwizzleW, \ |
1, \ |
3); \ |
ureg_emit_texture( ureg, insn.extended_token, target, 0 ); \ |
ureg_emit_dst( ureg, dst ); \ |
ureg_emit_src( ureg, src0 ); \ |
ureg_emit_src( ureg, src1 ); \ |
ureg_emit_src( ureg, src2 ); \ |
ureg_fixup_insn_size( ureg, insn.insn_token ); \ |
} |
#define OP14_TEX( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_dst dst, \ |
unsigned target, \ |
struct ureg_src src0, \ |
struct ureg_src src1, \ |
struct ureg_src src2, \ |
struct ureg_src src3 ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
struct ureg_emit_insn_result insn; \ |
insn = ureg_emit_insn(ureg, \ |
opcode, \ |
dst.Saturate, \ |
dst.Predicate, \ |
dst.PredNegate, \ |
dst.PredSwizzleX, \ |
dst.PredSwizzleY, \ |
dst.PredSwizzleZ, \ |
dst.PredSwizzleW, \ |
1, \ |
4); \ |
ureg_emit_texture( ureg, insn.extended_token, target, 0 ); \ |
ureg_emit_dst( ureg, dst ); \ |
ureg_emit_src( ureg, src0 ); \ |
ureg_emit_src( ureg, src1 ); \ |
ureg_emit_src( ureg, src2 ); \ |
ureg_emit_src( ureg, src3 ); \ |
ureg_fixup_insn_size( ureg, insn.insn_token ); \ |
} |
#define OP14_SAMPLE( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_dst dst, \ |
struct ureg_src src0, \ |
struct ureg_src src1, \ |
struct ureg_src src2, \ |
struct ureg_src src3 ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
unsigned target = TGSI_TEXTURE_UNKNOWN; \ |
struct ureg_emit_insn_result insn; \ |
insn = ureg_emit_insn(ureg, \ |
opcode, \ |
dst.Saturate, \ |
dst.Predicate, \ |
dst.PredNegate, \ |
dst.PredSwizzleX, \ |
dst.PredSwizzleY, \ |
dst.PredSwizzleZ, \ |
dst.PredSwizzleW, \ |
1, \ |
4); \ |
ureg_emit_texture( ureg, insn.extended_token, target, 0 ); \ |
ureg_emit_dst( ureg, dst ); \ |
ureg_emit_src( ureg, src0 ); \ |
ureg_emit_src( ureg, src1 ); \ |
ureg_emit_src( ureg, src2 ); \ |
ureg_emit_src( ureg, src3 ); \ |
ureg_fixup_insn_size( ureg, insn.insn_token ); \ |
} |
#define OP14( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_dst dst, \ |
struct ureg_src src0, \ |
struct ureg_src src1, \ |
struct ureg_src src2, \ |
struct ureg_src src3 ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
unsigned insn = ureg_emit_insn(ureg, \ |
opcode, \ |
dst.Saturate, \ |
dst.Predicate, \ |
dst.PredNegate, \ |
dst.PredSwizzleX, \ |
dst.PredSwizzleY, \ |
dst.PredSwizzleZ, \ |
dst.PredSwizzleW, \ |
1, \ |
4).insn_token; \ |
ureg_emit_dst( ureg, dst ); \ |
ureg_emit_src( ureg, src0 ); \ |
ureg_emit_src( ureg, src1 ); \ |
ureg_emit_src( ureg, src2 ); \ |
ureg_emit_src( ureg, src3 ); \ |
ureg_fixup_insn_size( ureg, insn ); \ |
} |
#define OP15( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_dst dst, \ |
struct ureg_src src0, \ |
struct ureg_src src1, \ |
struct ureg_src src2, \ |
struct ureg_src src3, \ |
struct ureg_src src4 ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
unsigned insn = ureg_emit_insn(ureg, \ |
opcode, \ |
dst.Saturate, \ |
dst.Predicate, \ |
dst.PredNegate, \ |
dst.PredSwizzleX, \ |
dst.PredSwizzleY, \ |
dst.PredSwizzleZ, \ |
dst.PredSwizzleW, \ |
1, \ |
5).insn_token; \ |
ureg_emit_dst( ureg, dst ); \ |
ureg_emit_src( ureg, src0 ); \ |
ureg_emit_src( ureg, src1 ); \ |
ureg_emit_src( ureg, src2 ); \ |
ureg_emit_src( ureg, src3 ); \ |
ureg_emit_src( ureg, src4 ); \ |
ureg_fixup_insn_size( ureg, insn ); \ |
} |
#define OP15_SAMPLE( op ) \ |
static INLINE void ureg_##op( struct ureg_program *ureg, \ |
struct ureg_dst dst, \ |
struct ureg_src src0, \ |
struct ureg_src src1, \ |
struct ureg_src src2, \ |
struct ureg_src src3, \ |
struct ureg_src src4 ) \ |
{ \ |
unsigned opcode = TGSI_OPCODE_##op; \ |
unsigned target = TGSI_TEXTURE_UNKNOWN; \ |
struct ureg_emit_insn_result insn; \ |
insn = ureg_emit_insn(ureg, \ |
opcode, \ |
dst.Saturate, \ |
dst.Predicate, \ |
dst.PredNegate, \ |
dst.PredSwizzleX, \ |
dst.PredSwizzleY, \ |
dst.PredSwizzleZ, \ |
dst.PredSwizzleW, \ |
1, \ |
5); \ |
ureg_emit_texture( ureg, insn.extended_token, target, 0 ); \ |
ureg_emit_dst( ureg, dst ); \ |
ureg_emit_src( ureg, src0 ); \ |
ureg_emit_src( ureg, src1 ); \ |
ureg_emit_src( ureg, src2 ); \ |
ureg_emit_src( ureg, src3 ); \ |
ureg_emit_src( ureg, src4 ); \ |
ureg_fixup_insn_size( ureg, insn.insn_token ); \ |
} |
/* Use a template include to generate a correctly-typed ureg_OP() |
* function for each TGSI opcode: |
*/ |
#include "tgsi_opcode_tmp.h" |
/*********************************************************************** |
* Inline helpers for manipulating register structs: |
*/ |
static INLINE struct ureg_src |
ureg_negate( struct ureg_src reg ) |
{ |
assert(reg.File != TGSI_FILE_NULL); |
reg.Negate ^= 1; |
return reg; |
} |
static INLINE struct ureg_src |
ureg_abs( struct ureg_src reg ) |
{ |
assert(reg.File != TGSI_FILE_NULL); |
reg.Absolute = 1; |
reg.Negate = 0; |
return reg; |
} |
static INLINE struct ureg_src |
ureg_swizzle( struct ureg_src reg, |
int x, int y, int z, int w ) |
{ |
unsigned swz = ( (reg.SwizzleX << 0) | |
(reg.SwizzleY << 2) | |
(reg.SwizzleZ << 4) | |
(reg.SwizzleW << 6)); |
assert(reg.File != TGSI_FILE_NULL); |
assert(x < 4); |
assert(y < 4); |
assert(z < 4); |
assert(w < 4); |
reg.SwizzleX = (swz >> (x*2)) & 0x3; |
reg.SwizzleY = (swz >> (y*2)) & 0x3; |
reg.SwizzleZ = (swz >> (z*2)) & 0x3; |
reg.SwizzleW = (swz >> (w*2)) & 0x3; |
return reg; |
} |
static INLINE struct ureg_src |
ureg_scalar( struct ureg_src reg, int x ) |
{ |
return ureg_swizzle(reg, x, x, x, x); |
} |
static INLINE struct ureg_dst |
ureg_writemask( struct ureg_dst reg, |
unsigned writemask ) |
{ |
assert(reg.File != TGSI_FILE_NULL); |
reg.WriteMask &= writemask; |
return reg; |
} |
static INLINE struct ureg_dst |
ureg_saturate( struct ureg_dst reg ) |
{ |
assert(reg.File != TGSI_FILE_NULL); |
reg.Saturate = 1; |
return reg; |
} |
static INLINE struct ureg_dst |
ureg_predicate(struct ureg_dst reg, |
boolean negate, |
unsigned swizzle_x, |
unsigned swizzle_y, |
unsigned swizzle_z, |
unsigned swizzle_w) |
{ |
assert(reg.File != TGSI_FILE_NULL); |
reg.Predicate = 1; |
reg.PredNegate = negate; |
reg.PredSwizzleX = swizzle_x; |
reg.PredSwizzleY = swizzle_y; |
reg.PredSwizzleZ = swizzle_z; |
reg.PredSwizzleW = swizzle_w; |
return reg; |
} |
static INLINE struct ureg_dst |
ureg_dst_indirect( struct ureg_dst reg, struct ureg_src addr ) |
{ |
assert(reg.File != TGSI_FILE_NULL); |
assert(addr.File == TGSI_FILE_ADDRESS || addr.File == TGSI_FILE_TEMPORARY); |
reg.Indirect = 1; |
reg.IndirectFile = addr.File; |
reg.IndirectIndex = addr.Index; |
reg.IndirectSwizzle = addr.SwizzleX; |
return reg; |
} |
static INLINE struct ureg_src |
ureg_src_indirect( struct ureg_src reg, struct ureg_src addr ) |
{ |
assert(reg.File != TGSI_FILE_NULL); |
assert(addr.File == TGSI_FILE_ADDRESS || addr.File == TGSI_FILE_TEMPORARY); |
reg.Indirect = 1; |
reg.IndirectFile = addr.File; |
reg.IndirectIndex = addr.Index; |
reg.IndirectSwizzle = addr.SwizzleX; |
return reg; |
} |
static INLINE struct ureg_src |
ureg_src_dimension( struct ureg_src reg, int index ) |
{ |
assert(reg.File != TGSI_FILE_NULL); |
reg.Dimension = 1; |
reg.DimIndirect = 0; |
reg.DimensionIndex = index; |
return reg; |
} |
static INLINE struct ureg_src |
ureg_src_dimension_indirect( struct ureg_src reg, struct ureg_src addr, |
int index ) |
{ |
assert(reg.File != TGSI_FILE_NULL); |
reg.Dimension = 1; |
reg.DimIndirect = 1; |
reg.DimensionIndex = index; |
reg.DimIndFile = addr.File; |
reg.DimIndIndex = addr.Index; |
reg.DimIndSwizzle = addr.SwizzleX; |
return reg; |
} |
static INLINE struct ureg_dst |
ureg_dst_array_offset( struct ureg_dst reg, int offset ) |
{ |
assert(reg.File == TGSI_FILE_TEMPORARY); |
reg.Index += offset; |
return reg; |
} |
static INLINE struct ureg_dst |
ureg_dst( struct ureg_src src ) |
{ |
struct ureg_dst dst; |
assert(!src.Indirect || |
(src.IndirectFile == TGSI_FILE_ADDRESS || |
src.IndirectFile == TGSI_FILE_TEMPORARY)); |
dst.File = src.File; |
dst.WriteMask = TGSI_WRITEMASK_XYZW; |
dst.IndirectFile = src.IndirectFile; |
dst.Indirect = src.Indirect; |
dst.IndirectIndex = src.IndirectIndex; |
dst.IndirectSwizzle = src.IndirectSwizzle; |
dst.Saturate = 0; |
dst.Predicate = 0; |
dst.PredNegate = 0; |
dst.PredSwizzleX = TGSI_SWIZZLE_X; |
dst.PredSwizzleY = TGSI_SWIZZLE_Y; |
dst.PredSwizzleZ = TGSI_SWIZZLE_Z; |
dst.PredSwizzleW = TGSI_SWIZZLE_W; |
dst.Index = src.Index; |
dst.ArrayID = src.ArrayID; |
return dst; |
} |
static INLINE struct ureg_src |
ureg_src_register(unsigned file, |
unsigned index) |
{ |
struct ureg_src src; |
src.File = file; |
src.SwizzleX = TGSI_SWIZZLE_X; |
src.SwizzleY = TGSI_SWIZZLE_Y; |
src.SwizzleZ = TGSI_SWIZZLE_Z; |
src.SwizzleW = TGSI_SWIZZLE_W; |
src.Indirect = 0; |
src.IndirectFile = TGSI_FILE_NULL; |
src.IndirectIndex = 0; |
src.IndirectSwizzle = 0; |
src.Absolute = 0; |
src.Index = index; |
src.Negate = 0; |
src.Dimension = 0; |
src.DimensionIndex = 0; |
src.DimIndirect = 0; |
src.DimIndFile = TGSI_FILE_NULL; |
src.DimIndIndex = 0; |
src.DimIndSwizzle = 0; |
src.ArrayID = 0; |
return src; |
} |
static INLINE struct ureg_src |
ureg_src( struct ureg_dst dst ) |
{ |
struct ureg_src src; |
src.File = dst.File; |
src.SwizzleX = TGSI_SWIZZLE_X; |
src.SwizzleY = TGSI_SWIZZLE_Y; |
src.SwizzleZ = TGSI_SWIZZLE_Z; |
src.SwizzleW = TGSI_SWIZZLE_W; |
src.Indirect = dst.Indirect; |
src.IndirectFile = dst.IndirectFile; |
src.IndirectIndex = dst.IndirectIndex; |
src.IndirectSwizzle = dst.IndirectSwizzle; |
src.Absolute = 0; |
src.Index = dst.Index; |
src.Negate = 0; |
src.Dimension = 0; |
src.DimensionIndex = 0; |
src.DimIndirect = 0; |
src.DimIndFile = TGSI_FILE_NULL; |
src.DimIndIndex = 0; |
src.DimIndSwizzle = 0; |
src.ArrayID = dst.ArrayID; |
return src; |
} |
static INLINE struct ureg_dst |
ureg_dst_undef( void ) |
{ |
struct ureg_dst dst; |
dst.File = TGSI_FILE_NULL; |
dst.WriteMask = 0; |
dst.Indirect = 0; |
dst.IndirectFile = TGSI_FILE_NULL; |
dst.IndirectIndex = 0; |
dst.IndirectSwizzle = 0; |
dst.Saturate = 0; |
dst.Predicate = 0; |
dst.PredNegate = 0; |
dst.PredSwizzleX = TGSI_SWIZZLE_X; |
dst.PredSwizzleY = TGSI_SWIZZLE_Y; |
dst.PredSwizzleZ = TGSI_SWIZZLE_Z; |
dst.PredSwizzleW = TGSI_SWIZZLE_W; |
dst.Index = 0; |
dst.ArrayID = 0; |
return dst; |
} |
static INLINE struct ureg_src |
ureg_src_undef( void ) |
{ |
struct ureg_src src; |
src.File = TGSI_FILE_NULL; |
src.SwizzleX = 0; |
src.SwizzleY = 0; |
src.SwizzleZ = 0; |
src.SwizzleW = 0; |
src.Indirect = 0; |
src.IndirectFile = TGSI_FILE_NULL; |
src.IndirectIndex = 0; |
src.IndirectSwizzle = 0; |
src.Absolute = 0; |
src.Index = 0; |
src.Negate = 0; |
src.Dimension = 0; |
src.DimensionIndex = 0; |
src.DimIndirect = 0; |
src.DimIndFile = TGSI_FILE_NULL; |
src.DimIndIndex = 0; |
src.DimIndSwizzle = 0; |
src.ArrayID = 0; |
return src; |
} |
static INLINE boolean |
ureg_src_is_undef( struct ureg_src src ) |
{ |
return src.File == TGSI_FILE_NULL; |
} |
static INLINE boolean |
ureg_dst_is_undef( struct ureg_dst dst ) |
{ |
return dst.File == TGSI_FILE_NULL; |
} |
#ifdef __cplusplus |
} |
#endif |
#endif |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_util.c |
---|
0,0 → 1,433 |
/************************************************************************** |
* |
* Copyright 2007 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 "util/u_debug.h" |
#include "pipe/p_shader_tokens.h" |
#include "tgsi_parse.h" |
#include "tgsi_util.h" |
union pointer_hack |
{ |
void *pointer; |
uint64_t uint64; |
}; |
void * |
tgsi_align_128bit( |
void *unaligned ) |
{ |
union pointer_hack ph; |
ph.uint64 = 0; |
ph.pointer = unaligned; |
ph.uint64 = (ph.uint64 + 15) & ~15; |
return ph.pointer; |
} |
unsigned |
tgsi_util_get_src_register_swizzle( |
const struct tgsi_src_register *reg, |
unsigned component ) |
{ |
switch( component ) { |
case 0: |
return reg->SwizzleX; |
case 1: |
return reg->SwizzleY; |
case 2: |
return reg->SwizzleZ; |
case 3: |
return reg->SwizzleW; |
default: |
assert( 0 ); |
} |
return 0; |
} |
unsigned |
tgsi_util_get_full_src_register_swizzle( |
const struct tgsi_full_src_register *reg, |
unsigned component ) |
{ |
return tgsi_util_get_src_register_swizzle( |
®->Register, |
component ); |
} |
void |
tgsi_util_set_src_register_swizzle( |
struct tgsi_src_register *reg, |
unsigned swizzle, |
unsigned component ) |
{ |
switch( component ) { |
case 0: |
reg->SwizzleX = swizzle; |
break; |
case 1: |
reg->SwizzleY = swizzle; |
break; |
case 2: |
reg->SwizzleZ = swizzle; |
break; |
case 3: |
reg->SwizzleW = swizzle; |
break; |
default: |
assert( 0 ); |
} |
} |
unsigned |
tgsi_util_get_full_src_register_sign_mode( |
const struct tgsi_full_src_register *reg, |
unsigned component ) |
{ |
unsigned sign_mode; |
if( reg->Register.Absolute ) { |
/* Consider only the post-abs negation. */ |
if( reg->Register.Negate ) { |
sign_mode = TGSI_UTIL_SIGN_SET; |
} |
else { |
sign_mode = TGSI_UTIL_SIGN_CLEAR; |
} |
} |
else { |
if( reg->Register.Negate ) { |
sign_mode = TGSI_UTIL_SIGN_TOGGLE; |
} |
else { |
sign_mode = TGSI_UTIL_SIGN_KEEP; |
} |
} |
return sign_mode; |
} |
void |
tgsi_util_set_full_src_register_sign_mode( |
struct tgsi_full_src_register *reg, |
unsigned sign_mode ) |
{ |
switch (sign_mode) |
{ |
case TGSI_UTIL_SIGN_CLEAR: |
reg->Register.Negate = 0; |
reg->Register.Absolute = 1; |
break; |
case TGSI_UTIL_SIGN_SET: |
reg->Register.Absolute = 1; |
reg->Register.Negate = 1; |
break; |
case TGSI_UTIL_SIGN_TOGGLE: |
reg->Register.Negate = 1; |
reg->Register.Absolute = 0; |
break; |
case TGSI_UTIL_SIGN_KEEP: |
reg->Register.Negate = 0; |
reg->Register.Absolute = 0; |
break; |
default: |
assert( 0 ); |
} |
} |
/** |
* Determine which channels of the specificed src register are effectively |
* used by this instruction. |
*/ |
unsigned |
tgsi_util_get_inst_usage_mask(const struct tgsi_full_instruction *inst, |
unsigned src_idx) |
{ |
const struct tgsi_full_src_register *src = &inst->Src[src_idx]; |
unsigned write_mask = inst->Dst[0].Register.WriteMask; |
unsigned read_mask; |
unsigned usage_mask; |
unsigned chan; |
switch (inst->Instruction.Opcode) { |
case TGSI_OPCODE_MOV: |
case TGSI_OPCODE_ARL: |
case TGSI_OPCODE_ARR: |
case TGSI_OPCODE_RCP: |
case TGSI_OPCODE_MUL: |
case TGSI_OPCODE_DIV: |
case TGSI_OPCODE_ADD: |
case TGSI_OPCODE_MIN: |
case TGSI_OPCODE_MAX: |
case TGSI_OPCODE_SLT: |
case TGSI_OPCODE_SGE: |
case TGSI_OPCODE_MAD: |
case TGSI_OPCODE_SUB: |
case TGSI_OPCODE_LRP: |
case TGSI_OPCODE_CND: |
case TGSI_OPCODE_FRC: |
case TGSI_OPCODE_CEIL: |
case TGSI_OPCODE_CLAMP: |
case TGSI_OPCODE_FLR: |
case TGSI_OPCODE_ROUND: |
case TGSI_OPCODE_POW: |
case TGSI_OPCODE_ABS: |
case TGSI_OPCODE_COS: |
case TGSI_OPCODE_SIN: |
case TGSI_OPCODE_DDX: |
case TGSI_OPCODE_DDY: |
case TGSI_OPCODE_SEQ: |
case TGSI_OPCODE_SGT: |
case TGSI_OPCODE_SLE: |
case TGSI_OPCODE_SNE: |
case TGSI_OPCODE_SSG: |
case TGSI_OPCODE_CMP: |
case TGSI_OPCODE_TRUNC: |
case TGSI_OPCODE_NOT: |
case TGSI_OPCODE_AND: |
case TGSI_OPCODE_OR: |
case TGSI_OPCODE_XOR: |
case TGSI_OPCODE_SAD: |
/* Channel-wise operations */ |
read_mask = write_mask; |
break; |
case TGSI_OPCODE_EX2: |
case TGSI_OPCODE_LG2: |
case TGSI_OPCODE_RCC: |
read_mask = TGSI_WRITEMASK_X; |
break; |
case TGSI_OPCODE_SCS: |
read_mask = write_mask & TGSI_WRITEMASK_XY ? TGSI_WRITEMASK_X : 0; |
break; |
case TGSI_OPCODE_EXP: |
case TGSI_OPCODE_LOG: |
read_mask = write_mask & TGSI_WRITEMASK_XYZ ? TGSI_WRITEMASK_X : 0; |
break; |
case TGSI_OPCODE_DP2A: |
read_mask = src_idx == 2 ? TGSI_WRITEMASK_X : TGSI_WRITEMASK_XY; |
break; |
case TGSI_OPCODE_DP2: |
read_mask = TGSI_WRITEMASK_XY; |
break; |
case TGSI_OPCODE_DP3: |
read_mask = TGSI_WRITEMASK_XYZ; |
break; |
case TGSI_OPCODE_DP4: |
read_mask = TGSI_WRITEMASK_XYZW; |
break; |
case TGSI_OPCODE_DPH: |
read_mask = src_idx == 0 ? TGSI_WRITEMASK_XYZ : TGSI_WRITEMASK_XYZW; |
break; |
case TGSI_OPCODE_TEX: |
case TGSI_OPCODE_TXD: |
case TGSI_OPCODE_TXB: |
case TGSI_OPCODE_TXL: |
case TGSI_OPCODE_TXP: |
if (src_idx == 0) { |
/* Note that the SHADOW variants use the Z component too */ |
switch (inst->Texture.Texture) { |
case TGSI_TEXTURE_1D: |
read_mask = TGSI_WRITEMASK_X; |
break; |
case TGSI_TEXTURE_SHADOW1D: |
read_mask = TGSI_WRITEMASK_XZ; |
break; |
case TGSI_TEXTURE_1D_ARRAY: |
case TGSI_TEXTURE_2D: |
case TGSI_TEXTURE_RECT: |
read_mask = TGSI_WRITEMASK_XY; |
break; |
case TGSI_TEXTURE_SHADOW1D_ARRAY: |
case TGSI_TEXTURE_SHADOW2D: |
case TGSI_TEXTURE_SHADOWRECT: |
case TGSI_TEXTURE_2D_ARRAY: |
case TGSI_TEXTURE_3D: |
case TGSI_TEXTURE_CUBE: |
case TGSI_TEXTURE_2D_MSAA: |
read_mask = TGSI_WRITEMASK_XYZ; |
break; |
case TGSI_TEXTURE_SHADOW2D_ARRAY: |
case TGSI_TEXTURE_CUBE_ARRAY: |
case TGSI_TEXTURE_SHADOWCUBE: |
case TGSI_TEXTURE_2D_ARRAY_MSAA: |
case TGSI_TEXTURE_SHADOWCUBE_ARRAY: |
read_mask = TGSI_WRITEMASK_XYZW; |
break; |
default: |
assert(0); |
read_mask = 0; |
} |
if (inst->Instruction.Opcode != TGSI_OPCODE_TEX) { |
read_mask |= TGSI_WRITEMASK_W; |
} |
} else { |
/* A safe approximation */ |
read_mask = TGSI_WRITEMASK_XYZW; |
} |
break; |
default: |
/* Assume all channels are read */ |
read_mask = TGSI_WRITEMASK_XYZW; |
break; |
} |
usage_mask = 0; |
for (chan = 0; chan < 4; ++chan) { |
if (read_mask & (1 << chan)) { |
usage_mask |= 1 << tgsi_util_get_full_src_register_swizzle(src, chan); |
} |
} |
return usage_mask; |
} |
/** |
* Convert a tgsi_ind_register into a tgsi_src_register |
*/ |
struct tgsi_src_register |
tgsi_util_get_src_from_ind(const struct tgsi_ind_register *reg) |
{ |
struct tgsi_src_register src = { 0 }; |
src.File = reg->File; |
src.Index = reg->Index; |
src.SwizzleX = reg->Swizzle; |
src.SwizzleY = reg->Swizzle; |
src.SwizzleZ = reg->Swizzle; |
src.SwizzleW = reg->Swizzle; |
return src; |
} |
/** |
* Return the dimension of the texture coordinates (layer included for array |
* textures), as well as the location of the shadow reference value or the |
* sample index. |
*/ |
int |
tgsi_util_get_texture_coord_dim(int tgsi_tex, int *shadow_or_sample) |
{ |
int dim; |
/* |
* Depending on the texture target, (src0.xyzw, src1.x) is interpreted |
* differently: |
* |
* (s, X, X, X, X), for BUFFER |
* (s, X, X, X, X), for 1D |
* (s, t, X, X, X), for 2D, RECT |
* (s, t, r, X, X), for 3D, CUBE |
* |
* (s, layer, X, X, X), for 1D_ARRAY |
* (s, t, layer, X, X), for 2D_ARRAY |
* (s, t, r, layer, X), for CUBE_ARRAY |
* |
* (s, X, shadow, X, X), for SHADOW1D |
* (s, t, shadow, X, X), for SHADOW2D, SHADOWRECT |
* (s, t, r, shadow, X), for SHADOWCUBE |
* |
* (s, layer, shadow, X, X), for SHADOW1D_ARRAY |
* (s, t, layer, shadow, X), for SHADOW2D_ARRAY |
* (s, t, r, layer, shadow), for SHADOWCUBE_ARRAY |
* |
* (s, t, sample, X, X), for 2D_MSAA |
* (s, t, layer, sample, X), for 2D_ARRAY_MSAA |
*/ |
switch (tgsi_tex) { |
case TGSI_TEXTURE_BUFFER: |
case TGSI_TEXTURE_1D: |
case TGSI_TEXTURE_SHADOW1D: |
dim = 1; |
break; |
case TGSI_TEXTURE_2D: |
case TGSI_TEXTURE_RECT: |
case TGSI_TEXTURE_1D_ARRAY: |
case TGSI_TEXTURE_SHADOW2D: |
case TGSI_TEXTURE_SHADOWRECT: |
case TGSI_TEXTURE_SHADOW1D_ARRAY: |
case TGSI_TEXTURE_2D_MSAA: |
dim = 2; |
break; |
case TGSI_TEXTURE_3D: |
case TGSI_TEXTURE_CUBE: |
case TGSI_TEXTURE_2D_ARRAY: |
case TGSI_TEXTURE_SHADOWCUBE: |
case TGSI_TEXTURE_SHADOW2D_ARRAY: |
case TGSI_TEXTURE_2D_ARRAY_MSAA: |
dim = 3; |
break; |
case TGSI_TEXTURE_CUBE_ARRAY: |
case TGSI_TEXTURE_SHADOWCUBE_ARRAY: |
dim = 4; |
break; |
default: |
assert(!"unknown texture target"); |
dim = 0; |
break; |
} |
if (shadow_or_sample) { |
switch (tgsi_tex) { |
case TGSI_TEXTURE_SHADOW1D: |
/* there is a gap */ |
*shadow_or_sample = 2; |
break; |
case TGSI_TEXTURE_SHADOW2D: |
case TGSI_TEXTURE_SHADOWRECT: |
case TGSI_TEXTURE_SHADOWCUBE: |
case TGSI_TEXTURE_SHADOW1D_ARRAY: |
case TGSI_TEXTURE_SHADOW2D_ARRAY: |
case TGSI_TEXTURE_SHADOWCUBE_ARRAY: |
case TGSI_TEXTURE_2D_MSAA: |
case TGSI_TEXTURE_2D_ARRAY_MSAA: |
*shadow_or_sample = dim; |
break; |
default: |
/* no shadow nor sample */ |
*shadow_or_sample = -1; |
break; |
} |
} |
return dim; |
} |
/contrib/sdk/sources/Mesa/src/gallium/auxiliary/tgsi/tgsi_util.h |
---|
0,0 → 1,89 |
/************************************************************************** |
* |
* Copyright 2007 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. |
* |
**************************************************************************/ |
#ifndef TGSI_UTIL_H |
#define TGSI_UTIL_H |
#if defined __cplusplus |
extern "C" { |
#endif |
struct tgsi_src_register; |
struct tgsi_full_src_register; |
struct tgsi_full_instruction; |
void * |
tgsi_align_128bit( |
void *unaligned ); |
unsigned |
tgsi_util_get_src_register_swizzle( |
const struct tgsi_src_register *reg, |
unsigned component ); |
unsigned |
tgsi_util_get_full_src_register_swizzle( |
const struct tgsi_full_src_register *reg, |
unsigned component ); |
void |
tgsi_util_set_src_register_swizzle( |
struct tgsi_src_register *reg, |
unsigned swizzle, |
unsigned component ); |
#define TGSI_UTIL_SIGN_CLEAR 0 /* Force positive */ |
#define TGSI_UTIL_SIGN_SET 1 /* Force negative */ |
#define TGSI_UTIL_SIGN_TOGGLE 2 /* Negate */ |
#define TGSI_UTIL_SIGN_KEEP 3 /* No change */ |
unsigned |
tgsi_util_get_full_src_register_sign_mode( |
const struct tgsi_full_src_register *reg, |
unsigned component ); |
void |
tgsi_util_set_full_src_register_sign_mode( |
struct tgsi_full_src_register *reg, |
unsigned sign_mode ); |
unsigned |
tgsi_util_get_inst_usage_mask(const struct tgsi_full_instruction *inst, |
unsigned src_idx); |
struct tgsi_src_register |
tgsi_util_get_src_from_ind(const struct tgsi_ind_register *reg); |
int |
tgsi_util_get_texture_coord_dim(int tgsi_tex, int *shadow_or_sample); |
#if defined __cplusplus |
} |
#endif |
#endif /* TGSI_UTIL_H */ |