// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // // 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 // // 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. #ifndef sw_Shader_hpp #define sw_Shader_hpp #include "Common/Types.hpp" #include <string> #include <vector> namespace sw { class Shader { public: enum ShaderType { SHADER_PIXEL = 0xFFFF, SHADER_VERTEX = 0xFFFE, SHADER_GEOMETRY = 0xFFFD }; enum Opcode { // Matches order in d3d9types.h OPCODE_NOP = 0, OPCODE_MOV, OPCODE_ADD, OPCODE_SUB, OPCODE_MAD, OPCODE_MUL, OPCODE_RCPX, OPCODE_RSQX, OPCODE_DP3, OPCODE_DP4, OPCODE_MIN, OPCODE_MAX, OPCODE_SLT, OPCODE_SGE, OPCODE_EXP2X, // D3DSIO_EXP OPCODE_LOG2X, // D3DSIO_LOG OPCODE_LIT, OPCODE_ATT, // D3DSIO_DST OPCODE_LRP, OPCODE_FRC, OPCODE_M4X4, OPCODE_M4X3, OPCODE_M3X4, OPCODE_M3X3, OPCODE_M3X2, OPCODE_CALL, OPCODE_CALLNZ, OPCODE_LOOP, OPCODE_RET, OPCODE_ENDLOOP, OPCODE_LABEL, OPCODE_DCL, OPCODE_POWX, OPCODE_CRS, OPCODE_SGN, OPCODE_ABS, OPCODE_NRM3, // D3DSIO_NRM OPCODE_SINCOS, OPCODE_REP, OPCODE_ENDREP, OPCODE_IF, OPCODE_IFC, OPCODE_ELSE, OPCODE_ENDIF, OPCODE_BREAK, OPCODE_BREAKC, OPCODE_MOVA, OPCODE_DEFB, OPCODE_DEFI, OPCODE_TEXCOORD = 64, OPCODE_TEXKILL, OPCODE_TEX, OPCODE_TEXBEM, OPCODE_TEXBEML, OPCODE_TEXREG2AR, OPCODE_TEXREG2GB, OPCODE_TEXM3X2PAD, OPCODE_TEXM3X2TEX, OPCODE_TEXM3X3PAD, OPCODE_TEXM3X3TEX, OPCODE_RESERVED0, OPCODE_TEXM3X3SPEC, OPCODE_TEXM3X3VSPEC, OPCODE_EXPP, OPCODE_LOGP, OPCODE_CND, OPCODE_DEF, OPCODE_TEXREG2RGB, OPCODE_TEXDP3TEX, OPCODE_TEXM3X2DEPTH, OPCODE_TEXDP3, OPCODE_TEXM3X3, OPCODE_TEXDEPTH, OPCODE_CMP0, // D3DSIO_CMP OPCODE_BEM, OPCODE_DP2ADD, OPCODE_DFDX, // D3DSIO_DSX OPCODE_DFDY, // D3DSIO_DSY OPCODE_TEXLDD, OPCODE_CMP, // D3DSIO_SETP OPCODE_TEXLDL, OPCODE_BREAKP, OPCODE_TEXSIZE, OPCODE_PHASE = 0xFFFD, OPCODE_COMMENT = 0xFFFE, OPCODE_END = 0xFFFF, OPCODE_PS_1_0 = 0xFFFF0100, OPCODE_PS_1_1 = 0xFFFF0101, OPCODE_PS_1_2 = 0xFFFF0102, OPCODE_PS_1_3 = 0xFFFF0103, OPCODE_PS_1_4 = 0xFFFF0104, OPCODE_PS_2_0 = 0xFFFF0200, OPCODE_PS_2_x = 0xFFFF0201, OPCODE_PS_3_0 = 0xFFFF0300, OPCODE_VS_1_0 = 0xFFFE0100, OPCODE_VS_1_1 = 0xFFFE0101, OPCODE_VS_2_0 = 0xFFFE0200, OPCODE_VS_2_x = 0xFFFE0201, OPCODE_VS_2_sw = 0xFFFE02FF, OPCODE_VS_3_0 = 0xFFFE0300, OPCODE_VS_3_sw = 0xFFFE03FF, OPCODE_NULL = 0x10000000, // Dead instruction, to be eliminated OPCODE_WHILE, OPCODE_ENDWHILE, OPCODE_COS, OPCODE_SIN, OPCODE_TAN, OPCODE_ACOS, OPCODE_ASIN, OPCODE_ATAN, OPCODE_ATAN2, OPCODE_COSH, OPCODE_SINH, OPCODE_TANH, OPCODE_ACOSH, OPCODE_ASINH, OPCODE_ATANH, OPCODE_DP1, OPCODE_DP2, OPCODE_TRUNC, OPCODE_FLOOR, OPCODE_ROUND, OPCODE_ROUNDEVEN, OPCODE_CEIL, OPCODE_SQRT, OPCODE_RSQ, OPCODE_LEN2, OPCODE_LEN3, OPCODE_LEN4, OPCODE_DIST1, OPCODE_DIST2, OPCODE_DIST3, OPCODE_DIST4, OPCODE_NRM2, OPCODE_NRM4, OPCODE_DIV, OPCODE_MOD, OPCODE_EXP2, OPCODE_LOG2, OPCODE_EXP, OPCODE_LOG, OPCODE_POW, OPCODE_F2B, // Float to bool OPCODE_B2F, // Bool to float OPCODE_F2I, // Float to int OPCODE_I2F, // Int to float OPCODE_F2U, // Float to uint OPCODE_U2F, // Uint to float OPCODE_I2B, // Int to bool OPCODE_B2I, // Bool to int OPCODE_DET2, OPCODE_DET3, OPCODE_DET4, OPCODE_ALL, OPCODE_ANY, OPCODE_NEG, OPCODE_NOT, OPCODE_OR, OPCODE_XOR, OPCODE_AND, OPCODE_EQ, OPCODE_NE, OPCODE_STEP, OPCODE_SMOOTH, OPCODE_ISNAN, OPCODE_ISINF, OPCODE_TEXOFFSET, OPCODE_TEXLDLOFFSET, OPCODE_TEXELFETCH, OPCODE_TEXELFETCHOFFSET, OPCODE_TEXGRAD, OPCODE_TEXGRADOFFSET, OPCODE_FLOATBITSTOINT, OPCODE_FLOATBITSTOUINT, OPCODE_INTBITSTOFLOAT, OPCODE_UINTBITSTOFLOAT, OPCODE_PACKSNORM2x16, OPCODE_PACKUNORM2x16, OPCODE_PACKHALF2x16, OPCODE_UNPACKSNORM2x16, OPCODE_UNPACKUNORM2x16, OPCODE_UNPACKHALF2x16, OPCODE_FORWARD1, OPCODE_FORWARD2, OPCODE_FORWARD3, OPCODE_FORWARD4, OPCODE_REFLECT1, OPCODE_REFLECT2, OPCODE_REFLECT3, OPCODE_REFLECT4, OPCODE_REFRACT1, OPCODE_REFRACT2, OPCODE_REFRACT3, OPCODE_REFRACT4, OPCODE_ICMP, OPCODE_UCMP, OPCODE_SELECT, OPCODE_EXTRACT, OPCODE_INSERT, OPCODE_DISCARD, OPCODE_FWIDTH, OPCODE_LEAVE, // Return before the end of the function OPCODE_CONTINUE, OPCODE_TEST, // Marks the end of the code that can be skipped by 'continue' OPCODE_SWITCH, OPCODE_ENDSWITCH, // Integer opcodes OPCODE_INEG, OPCODE_IABS, OPCODE_ISGN, OPCODE_IADD, OPCODE_ISUB, OPCODE_IMUL, OPCODE_IDIV, OPCODE_IMAD, OPCODE_IMOD, OPCODE_SHL, OPCODE_ISHR, OPCODE_IMIN, OPCODE_IMAX, // Unsigned integer opcodes OPCODE_UDIV, OPCODE_UMOD, OPCODE_USHR, OPCODE_UMIN, OPCODE_UMAX, }; static Opcode OPCODE_DP(int); static Opcode OPCODE_LEN(int); static Opcode OPCODE_DIST(int); static Opcode OPCODE_NRM(int); static Opcode OPCODE_FORWARD(int); static Opcode OPCODE_REFLECT(int); static Opcode OPCODE_REFRACT(int); enum Control { CONTROL_RESERVED0, CONTROL_GT, CONTROL_EQ, CONTROL_GE, CONTROL_LT, CONTROL_NE, CONTROL_LE, CONTROL_RESERVED1 }; enum SamplerType { SAMPLER_UNKNOWN, SAMPLER_1D, SAMPLER_2D, SAMPLER_CUBE, SAMPLER_VOLUME }; enum Usage // For vertex input/output declarations { USAGE_POSITION = 0, USAGE_BLENDWEIGHT = 1, USAGE_BLENDINDICES = 2, USAGE_NORMAL = 3, USAGE_PSIZE = 4, USAGE_TEXCOORD = 5, USAGE_TANGENT = 6, USAGE_BINORMAL = 7, USAGE_TESSFACTOR = 8, USAGE_POSITIONT = 9, USAGE_COLOR = 10, USAGE_FOG = 11, USAGE_DEPTH = 12, USAGE_SAMPLE = 13 }; enum ParameterType { PARAMETER_TEMP = 0, PARAMETER_INPUT = 1, PARAMETER_CONST = 2, PARAMETER_TEXTURE = 3, PARAMETER_ADDR = 3, PARAMETER_RASTOUT = 4, PARAMETER_ATTROUT = 5, PARAMETER_TEXCRDOUT = 6, PARAMETER_OUTPUT = 6, PARAMETER_CONSTINT = 7, PARAMETER_COLOROUT = 8, PARAMETER_DEPTHOUT = 9, PARAMETER_SAMPLER = 10, PARAMETER_CONST2 = 11, PARAMETER_CONST3 = 12, PARAMETER_CONST4 = 13, PARAMETER_CONSTBOOL = 14, PARAMETER_LOOP = 15, PARAMETER_TEMPFLOAT16 = 16, PARAMETER_MISCTYPE = 17, PARAMETER_LABEL = 18, PARAMETER_PREDICATE = 19, // PARAMETER_FLOAT1LITERAL, // PARAMETER_FLOAT2LITERAL, // PARAMETER_FLOAT3LITERAL, PARAMETER_FLOAT4LITERAL, PARAMETER_BOOL1LITERAL, // PARAMETER_BOOL2LITERAL, // PARAMETER_BOOL3LITERAL, // PARAMETER_BOOL4LITERAL, // PARAMETER_INT1LITERAL, // PARAMETER_INT2LITERAL, // PARAMETER_INT3LITERAL, PARAMETER_INT4LITERAL, PARAMETER_VOID }; enum Modifier { MODIFIER_NONE, MODIFIER_NEGATE, MODIFIER_BIAS, MODIFIER_BIAS_NEGATE, MODIFIER_SIGN, MODIFIER_SIGN_NEGATE, MODIFIER_COMPLEMENT, MODIFIER_X2, MODIFIER_X2_NEGATE, MODIFIER_DZ, MODIFIER_DW, MODIFIER_ABS, MODIFIER_ABS_NEGATE, MODIFIER_NOT }; enum Analysis { // Flags indicating whether an instruction is affected by an execution enable mask ANALYSIS_BRANCH = 0x00000001, ANALYSIS_BREAK = 0x00000002, ANALYSIS_CONTINUE = 0x00000004, ANALYSIS_LEAVE = 0x00000008, }; struct Parameter { union { struct { unsigned int index; // For registers types struct { ParameterType type : 8; unsigned int index; unsigned int swizzle : 8; unsigned int scale; bool deterministic; // Equal accross shader instances run in lockstep (e.g. unrollable loop couters) } rel; }; float value[4]; // For float constants int integer[4]; // For integer constants int boolean[4]; // For boolean constants struct { unsigned int label; // Label index unsigned int callSite; // Call index (per label) }; }; Parameter() : index(0), type(PARAMETER_VOID) { rel.type = PARAMETER_VOID; rel.index = 0; rel.swizzle = 0; rel.scale = 1; rel.deterministic = false; } std::string string(ShaderType shaderType, unsigned short version) const; std::string typeString(ShaderType shaderType, unsigned short version) const; std::string relativeString() const; ParameterType type : 8; }; struct DestinationParameter : Parameter { union { unsigned char mask; struct { bool x : 1; bool y : 1; bool z : 1; bool w : 1; }; }; DestinationParameter() : mask(0xF), integer(false), saturate(false), partialPrecision(false), centroid(false), shift(0) { } std::string modifierString() const; std::string shiftString() const; std::string maskString() const; bool integer : 1; bool saturate : 1; bool partialPrecision : 1; bool centroid : 1; signed char shift : 4; }; struct SourceParameter : Parameter { SourceParameter() : swizzle(0xE4), modifier(MODIFIER_NONE), bufferIndex(-1) { } std::string swizzleString() const; std::string preModifierString() const; std::string postModifierString() const; unsigned int swizzle : 8; Modifier modifier : 8; int bufferIndex : 8; }; struct Instruction { explicit Instruction(Opcode opcode); Instruction(const unsigned long *token, int size, unsigned char majorVersion); virtual ~Instruction(); void parseOperationToken(unsigned long token, unsigned char majorVersion); void parseDeclarationToken(unsigned long token); void parseDestinationToken(const unsigned long *token, unsigned char majorVersion); void parseSourceToken(int i, const unsigned long *token, unsigned char majorVersion); std::string string(ShaderType shaderType, unsigned short version) const; static std::string swizzleString(ParameterType type, unsigned char swizzle); std::string operationString(unsigned short version) const; std::string controlString() const; bool isBranch() const; bool isCall() const; bool isBreak() const; bool isLoopOrSwitch() const; bool isEndLoopOrSwitch() const; bool isPredicated() const; Opcode opcode; union { Control control; struct { unsigned char project : 1; unsigned char bias : 1; }; }; bool predicate; bool predicateNot; // Negative predicate unsigned char predicateSwizzle; bool coissue; SamplerType samplerType; Usage usage; unsigned char usageIndex; DestinationParameter dst; SourceParameter src[5]; union { unsigned int analysis; struct { // Keep in sync with Shader::Analysis flags unsigned int analysisBranch : 1; unsigned int analysisBreak : 1; unsigned int analysisContinue : 1; unsigned int analysisLeave : 1; }; }; }; Shader(); virtual ~Shader(); int getSerialID() const; size_t getLength() const; ShaderType getShaderType() const; unsigned short getVersion() const; void append(Instruction *instruction); void declareSampler(int i); const Instruction *getInstruction(unsigned int i) const; int size(unsigned long opcode) const; static int size(unsigned long opcode, unsigned short version); void print(const char *fileName, ...) const; void printInstruction(int index, const char *fileName) const; static bool maskContainsComponent(int mask, int component); static bool swizzleContainsComponent(int swizzle, int component); static bool swizzleContainsComponentMasked(int swizzle, int component, int mask); bool containsDynamicBranching() const; bool containsBreakInstruction() const; bool containsContinueInstruction() const; bool containsLeaveInstruction() const; bool containsDefineInstruction() const; bool usesSampler(int i) const; struct Semantic { Semantic(unsigned char usage = 0xFF, unsigned char index = 0xFF) : usage(usage), index(index), centroid(false) { } bool operator==(const Semantic &semantic) const { return usage == semantic.usage && index == semantic.index; } bool active() const { return usage != 0xFF; } unsigned char usage; unsigned char index; bool centroid; }; void optimize(); virtual void analyze() = 0; // FIXME: Private unsigned int dirtyConstantsF; unsigned int dirtyConstantsI; unsigned int dirtyConstantsB; bool dynamicallyIndexedTemporaries; bool dynamicallyIndexedInput; bool dynamicallyIndexedOutput; protected: void parse(const unsigned long *token); void optimizeLeave(); void optimizeCall(); void removeNull(); void analyzeDirtyConstants(); void analyzeDynamicBranching(); void analyzeSamplers(); void analyzeCallSites(); void analyzeDynamicIndexing(); void markFunctionAnalysis(unsigned int functionLabel, Analysis flag); ShaderType shaderType; union { unsigned short version; struct { unsigned char minorVersion; unsigned char majorVersion; }; }; std::vector<Instruction*> instruction; unsigned short usedSamplers; // Bit flags private: const int serialID; static volatile int serialCounter; bool dynamicBranching; bool containsBreak; bool containsContinue; bool containsLeave; bool containsDefine; }; } #endif // sw_Shader_hpp