-// 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"
}
}
- Shader::Opcode Shader::OPCODE_NRM(int i)
+ Shader::Opcode Shader::OPCODE_NRM(int i)
{
switch(i)
{
predicate = false;
predicateNot = false;
predicateSwizzle = 0xE4;
-
+
coissue = false;
samplerType = SAMPLER_UNKNOWN;
usage = USAGE_POSITION;
token++;
size--;
}
-
+
token++;
size--;
}
predicateNot = (Modifier)((*token & 0x0F000000) >> 24) == MODIFIER_NOT;
predicateSwizzle = (unsigned char)((*token & 0x00FF0000) >> 16);
-
+
token++;
size--;
}
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";
{
instructionString += " " + dst.string(shaderType, version) +
dst.relativeString() +
- dst.maskString();
+ dst.maskString();
}
for(int i = 0; i < 4; i++)
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();
}
}
{
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 "";
{
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);
}
src[i].rel.type = PARAMETER_VOID;
src[i].rel.swizzle = 0x00;
src[i].rel.scale = 1;
-
+
switch(opcode)
{
case OPCODE_DEF:
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";
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";
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";
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";
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";
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";
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";
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";
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);
}
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
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 "";
{
return opcode == OPCODE_IF || opcode == OPCODE_IFC;
}
-
+
bool Shader::Instruction::isCall() const
{
return opcode == OPCODE_CALL || opcode == OPCODE_CALLNZ;
majorVersion = (unsigned char)((token[0] & 0x0000FF00) >> 8);
shaderType = (ShaderType)((token[0] & 0xFFFF0000) >> 16);
- int length;
+ int length = 0;
if(shaderType == SHADER_VERTEX)
{
token += 1 + tokenCount;
}
}
-
+
int Shader::size(unsigned long opcode) const
{
return size(opcode, version);
ASSERT(false);
}
- static const char size[] =
+ static const signed char size[] =
{
0, // NOP = 0
2, // MOV
return containsLeave;
}
+ bool Shader::containsDefineInstruction() const
+ {
+ return containsDefine;
+ }
+
bool Shader::usesSampler(int index) const
{
return (usedSamplers & (1 << index)) != 0;
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());
dirtyConstantsB = instruction[i]->dst.index + 1;
}
break;
+ default:
+ break;
}
}
}
containsLeave = false;
containsBreak = false;
containsContinue = false;
+ containsDefine = false;
// Determine global presence of branching instructions
for(unsigned int i = 0; i < instruction.size(); i++)
{
containsLeave = true;
}
-
+
if(instruction[i]->isBreak())
{
containsBreak = true;
{
containsContinue = true;
}
+ case OPCODE_DEF:
+ case OPCODE_DEFB:
+ case OPCODE_DEFI:
+ containsDefine = true;
+ default:
+ break;
}
}
int breakDepth = 0;
int continueDepth = 0;
bool leaveReturn = false;
+ unsigned int functionBegin = 0;
for(unsigned int i = 0; i < instruction.size(); i++)
{
{
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;
{
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;
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)
{
}
}
- 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++)
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];
}
}
break;
+ default:
+ break;
}
}
}
{
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;
}
}
{
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;
}
}
}