| /************************************************************************** |
| * |
| * 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_SHADOWCUBE: |
| case TGSI_TEXTURE_2D_ARRAY_MSAA: |
| 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; |
| } |