OSDN Git Service

gl_VertexID implementation
[android-x86/external-swiftshader.git] / src / Shader / Shader.cpp
index aa5b30d..ff1482e 100644 (file)
@@ -1,13 +1,16 @@
-// SwiftShader Software Renderer
+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
 //
-// Copyright(c) 2005-2013 TransGaming Inc.
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
 //
-// All rights reserved. No part of this software may be copied, distributed, transmitted,
-// transcribed, stored in a retrieval system, translated into any human or computer
-// language by any means, or disclosed to third parties without the explicit written
-// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
-// or implied, including but not limited to any patent rights, are granted to you.
+//    http://www.apache.org/licenses/LICENSE-2.0
 //
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
 #include "Shader.hpp"
 
@@ -61,7 +64,7 @@ namespace sw
                }
        }
 
-       Shader::Opcode Shader::OPCODE_NRM(int i)        
+       Shader::Opcode Shader::OPCODE_NRM(int i)
        {
                switch(i)
                {
@@ -116,7 +119,7 @@ namespace sw
                predicate = false;
                predicateNot = false;
                predicateSwizzle = 0xE4;
-               
+
                coissue = false;
                samplerType = SAMPLER_UNKNOWN;
                usage = USAGE_POSITION;
@@ -159,7 +162,7 @@ namespace sw
                                        token++;
                                        size--;
                                }
-                               
+
                                token++;
                                size--;
                        }
@@ -170,7 +173,7 @@ namespace sw
 
                                predicateNot = (Modifier)((*token & 0x0F000000) >> 24) == MODIFIER_NOT;
                                predicateSwizzle = (unsigned char)((*token & 0x00FF0000) >> 16);
-                               
+
                                token++;
                                size--;
                        }
@@ -198,11 +201,11 @@ namespace sw
        std::string Shader::Instruction::string(ShaderType shaderType, unsigned short version) const
        {
                std::string instructionString;
-               
+
                if(opcode != OPCODE_DCL)
                {
                        instructionString += coissue ? "+ " : "";
-                       
+
                        if(predicate)
                        {
                                instructionString += predicateNot ? "(!p0" : "(p0";
@@ -216,7 +219,7 @@ namespace sw
                        {
                                instructionString += " " + dst.string(shaderType, version) +
                                                           dst.relativeString() +
-                                                          dst.maskString(); 
+                                                          dst.maskString();
                        }
 
                        for(int i = 0; i < 4; i++)
@@ -226,8 +229,8 @@ namespace sw
                                        instructionString += (dst.type != PARAMETER_VOID || i > 0) ? ", " : " ";
                                        instructionString += src[i].preModifierString() +
                                                                                 src[i].string(shaderType, version) +
-                                                                                src[i].relativeString() + 
-                                                                                src[i].postModifierString() + 
+                                                                                src[i].relativeString() +
+                                                                                src[i].postModifierString() +
                                                                                 src[i].swizzleString();
                                }
                        }
@@ -348,10 +351,10 @@ namespace sw
                {
                case 0:         return "";
                case 1:         return "_x2";
-               case 2:         return "_x4"; 
+               case 2:         return "_x4";
                case 3:         return "_x8";
                case -1:        return "_d2";
-               case -2:        return "_d4"; 
+               case -2:        return "_d4";
                case -3:        return "_d8";
                default:
                        return "";
@@ -456,6 +459,19 @@ namespace sw
                        {
                                return "[aL]";
                        }
+                       else if(rel.type == PARAMETER_CONST)
+                       {
+                               std::ostringstream buffer;
+                               buffer << rel.index;
+
+                               switch(rel.swizzle & 0x03)
+                               {
+                               case 0: return "[c" + buffer.str() + ".x]";
+                               case 1: return "[c" + buffer.str() + ".y]";
+                               case 2: return "[c" + buffer.str() + ".z]";
+                               case 3: return "[c" + buffer.str() + ".w]";
+                               }
+                       }
                        else ASSERT(false);
                }
 
@@ -614,7 +630,7 @@ namespace sw
                src[i].rel.type = PARAMETER_VOID;
                src[i].rel.swizzle = 0x00;
                src[i].rel.scale = 1;
-               
+
                switch(opcode)
                {
                case OPCODE_DEF:
@@ -735,12 +751,23 @@ namespace sw
                case OPCODE_NOP:                        return "nop";
                case OPCODE_MOV:                        return "mov";
                case OPCODE_ADD:                        return "add";
+               case OPCODE_IADD:                       return "iadd";
                case OPCODE_SUB:                        return "sub";
+               case OPCODE_ISUB:                       return "isub";
                case OPCODE_MAD:                        return "mad";
+               case OPCODE_IMAD:                       return "imad";
                case OPCODE_MUL:                        return "mul";
+               case OPCODE_IMUL:                       return "imul";
                case OPCODE_RCPX:                       return "rcpx";
                case OPCODE_DIV:                        return "div";
+               case OPCODE_IDIV:                       return "idiv";
+               case OPCODE_UDIV:                       return "udiv";
                case OPCODE_MOD:                        return "mod";
+               case OPCODE_IMOD:                       return "imod";
+               case OPCODE_UMOD:                       return "umod";
+               case OPCODE_SHL:                        return "shl";
+               case OPCODE_ISHR:                       return "ishr";
+               case OPCODE_USHR:                       return "ushr";
                case OPCODE_RSQX:                       return "rsqx";
                case OPCODE_SQRT:                       return "sqrt";
                case OPCODE_RSQ:                        return "rsq";
@@ -753,8 +780,15 @@ namespace sw
                case OPCODE_DIST4:                      return "dist4";
                case OPCODE_DP3:                        return "dp3";
                case OPCODE_DP4:                        return "dp4";
+               case OPCODE_DET2:                       return "det2";
+               case OPCODE_DET3:                       return "det3";
+               case OPCODE_DET4:                       return "det4";
                case OPCODE_MIN:                        return "min";
+               case OPCODE_IMIN:                       return "imin";
+               case OPCODE_UMIN:                       return "umin";
                case OPCODE_MAX:                        return "max";
+               case OPCODE_IMAX:                       return "imax";
+               case OPCODE_UMAX:                       return "umax";
                case OPCODE_SLT:                        return "slt";
                case OPCODE_SGE:                        return "sge";
                case OPCODE_EXP2X:                      return "exp2x";
@@ -764,6 +798,16 @@ namespace sw
                case OPCODE_LRP:                        return "lrp";
                case OPCODE_STEP:                       return "step";
                case OPCODE_SMOOTH:                     return "smooth";
+               case OPCODE_FLOATBITSTOINT:      return "floatBitsToInt";
+               case OPCODE_FLOATBITSTOUINT: return "floatBitsToUInt";
+               case OPCODE_INTBITSTOFLOAT:      return "intBitsToFloat";
+               case OPCODE_UINTBITSTOFLOAT: return "uintBitsToFloat";
+               case OPCODE_PACKSNORM2x16:       return "packSnorm2x16";
+               case OPCODE_PACKUNORM2x16:       return "packUnorm2x16";
+               case OPCODE_PACKHALF2x16:        return "packHalf2x16";
+               case OPCODE_UNPACKSNORM2x16: return "unpackSnorm2x16";
+               case OPCODE_UNPACKUNORM2x16: return "unpackUnorm2x16";
+               case OPCODE_UNPACKHALF2x16:      return "unpackHalf2x16";
                case OPCODE_FRC:                        return "frc";
                case OPCODE_M4X4:                       return "m4x4";
                case OPCODE_M4X3:                       return "m4x3";
@@ -780,7 +824,9 @@ namespace sw
                case OPCODE_POWX:                       return "powx";
                case OPCODE_CRS:                        return "crs";
                case OPCODE_SGN:                        return "sgn";
+               case OPCODE_ISGN:                       return "isgn";
                case OPCODE_ABS:                        return "abs";
+               case OPCODE_IABS:                       return "iabs";
                case OPCODE_NRM2:                       return "nrm2";
                case OPCODE_NRM3:                       return "nrm3";
                case OPCODE_NRM4:                       return "nrm4";
@@ -825,6 +871,7 @@ namespace sw
                case OPCODE_TEXDEPTH:           return "texdepth";
                case OPCODE_CMP0:                       return "cmp0";
                case OPCODE_ICMP:                       return "icmp";
+               case OPCODE_UCMP:                       return "ucmp";
                case OPCODE_SELECT:                     return "select";
                case OPCODE_EXTRACT:            return "extract";
                case OPCODE_INSERT:                     return "insert";
@@ -836,7 +883,14 @@ namespace sw
                case OPCODE_TEXLDD:                     return "texldd";
                case OPCODE_CMP:                        return "cmp";
                case OPCODE_TEXLDL:                     return "texldl";
+               case OPCODE_TEXOFFSET:          return "texoffset";
+               case OPCODE_TEXLDLOFFSET:       return "texldloffset";
+               case OPCODE_TEXELFETCH:         return "texelfetch";
+               case OPCODE_TEXELFETCHOFFSET: return "texelfetchoffset";
+               case OPCODE_TEXGRAD:            return "texgrad";
+               case OPCODE_TEXGRADOFFSET:      return "texgradoffset";
                case OPCODE_BREAKP:                     return "breakp";
+               case OPCODE_TEXSIZE:        return "texsize";
                case OPCODE_PHASE:                      return "phase";
                case OPCODE_COMMENT:            return "comment";
                case OPCODE_END:                        return "end";
@@ -864,10 +918,18 @@ namespace sw
                case OPCODE_ASIN:           return "asin";
                case OPCODE_ATAN:           return "atan";
                case OPCODE_ATAN2:          return "atan2";
+               case OPCODE_COSH:           return "cosh";
+               case OPCODE_SINH:           return "sinh";
+               case OPCODE_TANH:           return "tanh";
+               case OPCODE_ACOSH:          return "acosh";
+               case OPCODE_ASINH:          return "asinh";
+               case OPCODE_ATANH:          return "atanh";
                case OPCODE_DP1:            return "dp1";
                case OPCODE_DP2:            return "dp2";
                case OPCODE_TRUNC:          return "trunc";
                case OPCODE_FLOOR:          return "floor";
+               case OPCODE_ROUND:          return "round";
+               case OPCODE_ROUNDEVEN:      return "roundEven";
                case OPCODE_CEIL:           return "ceil";
                case OPCODE_EXP2:           return "exp2";
                case OPCODE_LOG2:           return "log2";
@@ -876,12 +938,24 @@ namespace sw
                case OPCODE_POW:            return "pow";
                case OPCODE_F2B:            return "f2b";
                case OPCODE_B2F:            return "b2f";
+               case OPCODE_F2I:            return "f2i";
+               case OPCODE_I2F:            return "i2f";
+               case OPCODE_F2U:            return "f2u";
+               case OPCODE_U2F:            return "u2f";
+               case OPCODE_B2I:            return "b2i";
+               case OPCODE_I2B:            return "i2b";
                case OPCODE_ALL:            return "all";
                case OPCODE_ANY:            return "any";
+               case OPCODE_NEG:            return "neg";
+               case OPCODE_INEG:           return "ineg";
+               case OPCODE_ISNAN:          return "isnan";
+               case OPCODE_ISINF:          return "isinf";
                case OPCODE_NOT:            return "not";
                case OPCODE_OR:             return "or";
                case OPCODE_XOR:            return "xor";
                case OPCODE_AND:            return "and";
+               case OPCODE_EQ:             return "eq";
+               case OPCODE_NE:             return "neq";
                case OPCODE_FORWARD1:       return "forward1";
                case OPCODE_FORWARD2:       return "forward2";
                case OPCODE_FORWARD3:       return "forward3";
@@ -897,6 +971,8 @@ namespace sw
                case OPCODE_LEAVE:          return "leave";
                case OPCODE_CONTINUE:       return "continue";
                case OPCODE_TEST:           return "test";
+               case OPCODE_SWITCH:         return "switch";
+               case OPCODE_ENDSWITCH:      return "endswitch";
                default:
                        ASSERT(false);
                }
@@ -942,7 +1018,7 @@ namespace sw
                else if(type != PARAMETER_RASTOUT && !(type == PARAMETER_ADDR && shaderType == SHADER_VERTEX) && type != PARAMETER_LOOP && type != PARAMETER_PREDICATE && type != PARAMETER_MISCTYPE)
                {
                        buffer << index;
-                       
+
                        return typeString(shaderType, version) + buffer.str();
                }
                else
@@ -983,9 +1059,14 @@ namespace sw
                case PARAMETER_LOOP:                    return "aL";
        //      case PARAMETER_TEMPFLOAT16:             return "";
                case PARAMETER_MISCTYPE:
-                       if(index == 0)                          return "vPos";
-                       else if(index == 1)                     return "vFace";
-                       else                                            ASSERT(false);
+                       switch(index)
+                       {
+                       case VPosIndex:                         return "vPos";
+                       case VFaceIndex:                        return "vFace";
+                       case InstanceIDIndex:           return "iID";
+                       case VertexIDIndex:                     return "vID";
+                       default: ASSERT(false);
+                       }
                case PARAMETER_LABEL:                   return "l";
                case PARAMETER_PREDICATE:               return "p0";
                case PARAMETER_FLOAT4LITERAL:   return "";
@@ -1003,7 +1084,7 @@ namespace sw
        {
                return opcode == OPCODE_IF || opcode == OPCODE_IFC;
        }
-       
+
        bool Shader::Instruction::isCall() const
        {
                return opcode == OPCODE_CALL || opcode == OPCODE_CALLNZ;
@@ -1053,7 +1134,7 @@ namespace sw
                majorVersion = (unsigned char)((token[0] & 0x0000FF00) >> 8);
                shaderType = (ShaderType)((token[0] & 0xFFFF0000) >> 16);
 
-               int length;
+               int length = 0;
 
                if(shaderType == SHADER_VERTEX)
                {
@@ -1084,7 +1165,7 @@ namespace sw
                        token += 1 + tokenCount;
                }
        }
-       
+
        int Shader::size(unsigned long opcode) const
        {
                return size(opcode, version);
@@ -1097,7 +1178,7 @@ namespace sw
                        ASSERT(false);
                }
 
-               static const char size[] =
+               static const signed char size[] =
                {
                        0,   // NOP = 0
                        2,   // MOV
@@ -1317,6 +1398,11 @@ namespace sw
                return containsLeave;
        }
 
+       bool Shader::containsDefineInstruction() const
+       {
+               return containsDefine;
+       }
+
        bool Shader::usesSampler(int index) const
        {
                return (usedSamplers & (1 << index)) != 0;
@@ -1376,7 +1462,7 @@ namespace sw
                usedSamplers |= 1 << i;
        }
 
-       const Shader::Instruction *Shader::getInstruction(unsigned int i) const
+       const Shader::Instruction *Shader::getInstruction(size_t i) const
        {
                ASSERT(i < instruction.size());
 
@@ -1515,6 +1601,8 @@ namespace sw
                                        dirtyConstantsB = instruction[i]->dst.index + 1;
                                }
                                break;
+                       default:
+                               break;
                        }
                }
        }
@@ -1525,6 +1613,7 @@ namespace sw
                containsLeave = false;
                containsBreak = false;
                containsContinue = false;
+               containsDefine = false;
 
                // Determine global presence of branching instructions
                for(unsigned int i = 0; i < instruction.size(); i++)
@@ -1549,7 +1638,7 @@ namespace sw
                                {
                                        containsLeave = true;
                                }
-                               
+
                                if(instruction[i]->isBreak())
                                {
                                        containsBreak = true;
@@ -1559,6 +1648,12 @@ namespace sw
                                {
                                        containsContinue = true;
                                }
+                       case OPCODE_DEF:
+                       case OPCODE_DEFB:
+                       case OPCODE_DEFI:
+                               containsDefine = true;
+                       default:
+                               break;
                        }
                }
 
@@ -1567,6 +1662,7 @@ namespace sw
                int breakDepth = 0;
                int continueDepth = 0;
                bool leaveReturn = false;
+               unsigned int functionBegin = 0;
 
                for(unsigned int i = 0; i < instruction.size(); i++)
                {
@@ -1595,17 +1691,17 @@ namespace sw
                        {
                                breakDepth++;
                        }
-                       else if(instruction[i]->isEndLoop())
-                       {
-                               breakDepth--;
-                       }
 
                        if(breakDepth > 0)
                        {
-                               if(instruction[i]->isLoop())   // Nested loop, don't make the end of it disable the break execution mask
+                               if(instruction[i]->isLoop() || instruction[i]->opcode == OPCODE_SWITCH)   // Nested loop or switch, don't make the end of it disable the break execution mask
                                {
                                        breakDepth++;
                                }
+                               else if(instruction[i]->isEndLoop() || instruction[i]->opcode == OPCODE_ENDSWITCH)
+                               {
+                                       breakDepth--;
+                               }
 
                                instruction[i]->analysisBreak = true;
 
@@ -1620,17 +1716,17 @@ namespace sw
                        {
                                continueDepth++;
                        }
-                       else if(instruction[i]->isEndLoop())
-                       {
-                               continueDepth--;
-                       }
 
                        if(continueDepth > 0)
                        {
-                               if(instruction[i]->isLoop())   // Nested loop, don't make the end of it disable the break execution mask
+                               if(instruction[i]->isLoop() || instruction[i]->opcode == OPCODE_SWITCH)   // Nested loop or switch, don't make the end of it disable the break execution mask
                                {
                                        continueDepth++;
                                }
+                               else if(instruction[i]->isEndLoop() || instruction[i]->opcode == OPCODE_ENDSWITCH)
+                               {
+                                       continueDepth--;
+                               }
 
                                instruction[i]->analysisContinue = true;
 
@@ -1644,11 +1740,29 @@ namespace sw
                        if(instruction[i]->opcode == OPCODE_LEAVE)
                        {
                                leaveReturn = true;
+
+                               // Mark loop body instructions prior to the return statement
+                               for(unsigned int l = functionBegin; l < i; l++)
+                               {
+                                       if(instruction[l]->isLoop())
+                                       {
+                                               for(unsigned int r = l + 1; r < i; r++)
+                                               {
+                                                       instruction[r]->analysisLeave = true;
+                                               }
+
+                                               break;
+                                       }
+                               }
                        }
                        else if(instruction[i]->opcode == OPCODE_RET)   // End of the function
                        {
                                leaveReturn = false;
                        }
+                       else if(instruction[i]->opcode == OPCODE_LABEL)
+                       {
+                               functionBegin = i;
+                       }
 
                        if(leaveReturn)
                        {
@@ -1662,7 +1776,7 @@ namespace sw
                }
        }
 
-       void Shader::markFunctionAnalysis(int functionLabel, Analysis flag)
+       void Shader::markFunctionAnalysis(unsigned int functionLabel, Analysis flag)
        {
                bool marker = false;
                for(unsigned int i = 0; i < instruction.size(); i++)
@@ -1710,6 +1824,12 @@ namespace sw
                        case OPCODE_TEXM3X2DEPTH:
                        case OPCODE_TEXLDD:
                        case OPCODE_TEXLDL:
+                       case OPCODE_TEXOFFSET:
+                       case OPCODE_TEXLDLOFFSET:
+                       case OPCODE_TEXELFETCH:
+                       case OPCODE_TEXELFETCHOFFSET:
+                       case OPCODE_TEXGRAD:
+                       case OPCODE_TEXGRADOFFSET:
                                {
                                        Parameter &dst = instruction[i]->dst;
                                        Parameter &src1 = instruction[i]->src[1];
@@ -1724,6 +1844,8 @@ namespace sw
                                        }
                                }
                                break;
+                       default:
+                               break;
                        }
                }
        }
@@ -1755,13 +1877,15 @@ namespace sw
                {
                        if(instruction[i]->dst.rel.type == PARAMETER_ADDR ||
                           instruction[i]->dst.rel.type == PARAMETER_LOOP ||
-                          instruction[i]->dst.rel.type == PARAMETER_TEMP)
+                          instruction[i]->dst.rel.type == PARAMETER_TEMP ||
+                          instruction[i]->dst.rel.type == PARAMETER_CONST)
                        {
                                switch(instruction[i]->dst.type)
                                {
                                case PARAMETER_TEMP:   dynamicallyIndexedTemporaries = true; break;
                                case PARAMETER_INPUT:  dynamicallyIndexedInput = true;       break;
                                case PARAMETER_OUTPUT: dynamicallyIndexedOutput = true;      break;
+                               default: break;
                                }
                        }
 
@@ -1769,13 +1893,15 @@ namespace sw
                        {
                                if(instruction[i]->src[j].rel.type == PARAMETER_ADDR ||
                                   instruction[i]->src[j].rel.type == PARAMETER_LOOP ||
-                                  instruction[i]->src[j].rel.type == PARAMETER_TEMP)
+                                  instruction[i]->src[j].rel.type == PARAMETER_TEMP ||
+                                  instruction[i]->src[j].rel.type == PARAMETER_CONST)
                                {
                                        switch(instruction[i]->src[j].type)
                                        {
                                        case PARAMETER_TEMP:   dynamicallyIndexedTemporaries = true; break;
                                        case PARAMETER_INPUT:  dynamicallyIndexedInput = true;       break;
                                        case PARAMETER_OUTPUT: dynamicallyIndexedOutput = true;      break;
+                                       default: break;
                                        }
                                }
                        }