|  | // 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. | 
|  |  | 
|  | #include "VertexShader.hpp" | 
|  |  | 
|  | #include "Renderer/Vertex.hpp" | 
|  | #include "Common/Debug.hpp" | 
|  |  | 
|  | #include <string.h> | 
|  |  | 
|  | namespace sw | 
|  | { | 
|  | VertexShader::VertexShader(const VertexShader *vs) : Shader() | 
|  | { | 
|  | shaderModel = 0x0300; | 
|  | positionRegister = Pos; | 
|  | pointSizeRegister = Unused; | 
|  | instanceIdDeclared = false; | 
|  | vertexIdDeclared = false; | 
|  | textureSampling = false; | 
|  |  | 
|  | for(int i = 0; i < MAX_VERTEX_INPUTS; i++) | 
|  | { | 
|  | input[i] = Semantic(); | 
|  | attribType[i] = ATTRIBTYPE_FLOAT; | 
|  | } | 
|  |  | 
|  | if(vs)   // Make a copy | 
|  | { | 
|  | for(size_t i = 0; i < vs->getLength(); i++) | 
|  | { | 
|  | append(new sw::Shader::Instruction(*vs->getInstruction(i))); | 
|  | } | 
|  |  | 
|  | memcpy(output, vs->output, sizeof(output)); | 
|  | memcpy(input, vs->input, sizeof(input)); | 
|  | memcpy(attribType, vs->attribType, sizeof(attribType)); | 
|  | positionRegister = vs->positionRegister; | 
|  | pointSizeRegister = vs->pointSizeRegister; | 
|  | instanceIdDeclared = vs->instanceIdDeclared; | 
|  | vertexIdDeclared = vs->vertexIdDeclared; | 
|  | usedSamplers = vs->usedSamplers; | 
|  |  | 
|  | optimize(); | 
|  | analyze(); | 
|  | } | 
|  | } | 
|  |  | 
|  | VertexShader::VertexShader(const unsigned long *token) : Shader() | 
|  | { | 
|  | parse(token); | 
|  |  | 
|  | positionRegister = Pos; | 
|  | pointSizeRegister = Unused; | 
|  | instanceIdDeclared = false; | 
|  | vertexIdDeclared = false; | 
|  | textureSampling = false; | 
|  |  | 
|  | for(int i = 0; i < MAX_VERTEX_INPUTS; i++) | 
|  | { | 
|  | input[i] = Semantic(); | 
|  | attribType[i] = ATTRIBTYPE_FLOAT; | 
|  | } | 
|  |  | 
|  | optimize(); | 
|  | analyze(); | 
|  | } | 
|  |  | 
|  | VertexShader::~VertexShader() | 
|  | { | 
|  | } | 
|  |  | 
|  | int VertexShader::validate(const unsigned long *const token) | 
|  | { | 
|  | if(!token) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | unsigned short version = (unsigned short)(token[0] & 0x0000FFFF); | 
|  | unsigned char majorVersion = (unsigned char)((token[0] & 0x0000FF00) >> 8); | 
|  | ShaderType shaderType = (ShaderType)((token[0] & 0xFFFF0000) >> 16); | 
|  |  | 
|  | if(shaderType != SHADER_VERTEX || majorVersion > 3) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int instructionCount = 1; | 
|  |  | 
|  | for(int i = 0; token[i] != 0x0000FFFF; i++) | 
|  | { | 
|  | if((token[i] & 0x0000FFFF) == 0x0000FFFE)   // Comment token | 
|  | { | 
|  | int length = (token[i] & 0x7FFF0000) >> 16; | 
|  |  | 
|  | i += length; | 
|  | } | 
|  | else | 
|  | { | 
|  | Shader::Opcode opcode = (Shader::Opcode)(token[i] & 0x0000FFFF); | 
|  |  | 
|  | switch(opcode) | 
|  | { | 
|  | case Shader::OPCODE_TEXCOORD: | 
|  | case Shader::OPCODE_TEXKILL: | 
|  | case Shader::OPCODE_TEX: | 
|  | case Shader::OPCODE_TEXBEM: | 
|  | case Shader::OPCODE_TEXBEML: | 
|  | case Shader::OPCODE_TEXREG2AR: | 
|  | case Shader::OPCODE_TEXREG2GB: | 
|  | case Shader::OPCODE_TEXM3X2PAD: | 
|  | case Shader::OPCODE_TEXM3X2TEX: | 
|  | case Shader::OPCODE_TEXM3X3PAD: | 
|  | case Shader::OPCODE_TEXM3X3TEX: | 
|  | case Shader::OPCODE_RESERVED0: | 
|  | case Shader::OPCODE_TEXM3X3SPEC: | 
|  | case Shader::OPCODE_TEXM3X3VSPEC: | 
|  | case Shader::OPCODE_TEXREG2RGB: | 
|  | case Shader::OPCODE_TEXDP3TEX: | 
|  | case Shader::OPCODE_TEXM3X2DEPTH: | 
|  | case Shader::OPCODE_TEXDP3: | 
|  | case Shader::OPCODE_TEXM3X3: | 
|  | case Shader::OPCODE_TEXDEPTH: | 
|  | case Shader::OPCODE_CMP0: | 
|  | case Shader::OPCODE_BEM: | 
|  | case Shader::OPCODE_DP2ADD: | 
|  | case Shader::OPCODE_DFDX: | 
|  | case Shader::OPCODE_DFDY: | 
|  | case Shader::OPCODE_TEXLDD: | 
|  | return 0;   // Unsupported operation | 
|  | default: | 
|  | instructionCount++; | 
|  | break; | 
|  | } | 
|  |  | 
|  | i += size(token[i], version); | 
|  | } | 
|  | } | 
|  |  | 
|  | return instructionCount; | 
|  | } | 
|  |  | 
|  | bool VertexShader::containsTextureSampling() const | 
|  | { | 
|  | return textureSampling; | 
|  | } | 
|  |  | 
|  | void VertexShader::setInput(int inputIdx, const sw::Shader::Semantic& semantic, AttribType aType) | 
|  | { | 
|  | input[inputIdx] = semantic; | 
|  | attribType[inputIdx] = aType; | 
|  | } | 
|  |  | 
|  | void VertexShader::setOutput(int outputIdx, int nbComponents, const sw::Shader::Semantic& semantic) | 
|  | { | 
|  | for(int i = 0; i < nbComponents; ++i) | 
|  | { | 
|  | output[outputIdx][i] = semantic; | 
|  | } | 
|  | } | 
|  |  | 
|  | void VertexShader::setPositionRegister(int posReg) | 
|  | { | 
|  | setOutput(posReg, 4, sw::Shader::Semantic(sw::Shader::USAGE_POSITION, 0)); | 
|  | positionRegister = posReg; | 
|  | } | 
|  |  | 
|  | void VertexShader::setPointSizeRegister(int ptSizeReg) | 
|  | { | 
|  | setOutput(ptSizeReg, 4, sw::Shader::Semantic(sw::Shader::USAGE_PSIZE, 0)); | 
|  | pointSizeRegister = ptSizeReg; | 
|  | } | 
|  |  | 
|  | const sw::Shader::Semantic& VertexShader::getInput(int inputIdx) const | 
|  | { | 
|  | return input[inputIdx]; | 
|  | } | 
|  |  | 
|  | VertexShader::AttribType VertexShader::getAttribType(int inputIdx) const | 
|  | { | 
|  | return attribType[inputIdx]; | 
|  | } | 
|  |  | 
|  | const sw::Shader::Semantic& VertexShader::getOutput(int outputIdx, int component) const | 
|  | { | 
|  | return output[outputIdx][component]; | 
|  | } | 
|  |  | 
|  | void VertexShader::analyze() | 
|  | { | 
|  | analyzeInput(); | 
|  | analyzeOutput(); | 
|  | analyzeDirtyConstants(); | 
|  | analyzeTextureSampling(); | 
|  | analyzeDynamicBranching(); | 
|  | analyzeSamplers(); | 
|  | analyzeCallSites(); | 
|  | analyzeIndirectAddressing(); | 
|  | } | 
|  |  | 
|  | void VertexShader::analyzeInput() | 
|  | { | 
|  | for(unsigned int i = 0; i < instruction.size(); i++) | 
|  | { | 
|  | if(instruction[i]->opcode == Shader::OPCODE_DCL && | 
|  | instruction[i]->dst.type == Shader::PARAMETER_INPUT) | 
|  | { | 
|  | int index = instruction[i]->dst.index; | 
|  |  | 
|  | input[index] = Semantic(instruction[i]->usage, instruction[i]->usageIndex); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void VertexShader::analyzeOutput() | 
|  | { | 
|  | if(shaderModel < 0x0300) | 
|  | { | 
|  | output[Pos][0] = Semantic(Shader::USAGE_POSITION, 0); | 
|  | output[Pos][1] = Semantic(Shader::USAGE_POSITION, 0); | 
|  | output[Pos][2] = Semantic(Shader::USAGE_POSITION, 0); | 
|  | output[Pos][3] = Semantic(Shader::USAGE_POSITION, 0); | 
|  |  | 
|  | for(const auto &inst : instruction) | 
|  | { | 
|  | const DestinationParameter &dst = inst->dst; | 
|  |  | 
|  | switch(dst.type) | 
|  | { | 
|  | case Shader::PARAMETER_RASTOUT: | 
|  | switch(dst.index) | 
|  | { | 
|  | case 0: | 
|  | // Position already assumed written | 
|  | break; | 
|  | case 1: | 
|  | output[Fog][0] = Semantic(Shader::USAGE_FOG, 0); | 
|  | break; | 
|  | case 2: | 
|  | output[Pts][1] = Semantic(Shader::USAGE_PSIZE, 0); | 
|  | pointSizeRegister = Pts; | 
|  | break; | 
|  | default: ASSERT(false); | 
|  | } | 
|  | break; | 
|  | case Shader::PARAMETER_ATTROUT: | 
|  | if(dst.index == 0) | 
|  | { | 
|  | if(dst.x) output[C0][0] = Semantic(Shader::USAGE_COLOR, 0); | 
|  | if(dst.y) output[C0][1] = Semantic(Shader::USAGE_COLOR, 0); | 
|  | if(dst.z) output[C0][2] = Semantic(Shader::USAGE_COLOR, 0); | 
|  | if(dst.w) output[C0][3] = Semantic(Shader::USAGE_COLOR, 0); | 
|  | } | 
|  | else if(dst.index == 1) | 
|  | { | 
|  | if(dst.x) output[C1][0] = Semantic(Shader::USAGE_COLOR, 1); | 
|  | if(dst.y) output[C1][1] = Semantic(Shader::USAGE_COLOR, 1); | 
|  | if(dst.z) output[C1][2] = Semantic(Shader::USAGE_COLOR, 1); | 
|  | if(dst.w) output[C1][3] = Semantic(Shader::USAGE_COLOR, 1); | 
|  | } | 
|  | else ASSERT(false); | 
|  | break; | 
|  | case Shader::PARAMETER_TEXCRDOUT: | 
|  | if(dst.x) output[T0 + dst.index][0] = Semantic(Shader::USAGE_TEXCOORD, dst.index); | 
|  | if(dst.y) output[T0 + dst.index][1] = Semantic(Shader::USAGE_TEXCOORD, dst.index); | 
|  | if(dst.z) output[T0 + dst.index][2] = Semantic(Shader::USAGE_TEXCOORD, dst.index); | 
|  | if(dst.w) output[T0 + dst.index][3] = Semantic(Shader::USAGE_TEXCOORD, dst.index); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | else   // Shader Model 3.0 input declaration | 
|  | { | 
|  | for(const auto &inst : instruction) | 
|  | { | 
|  | if(inst->opcode == Shader::OPCODE_DCL && | 
|  | inst->dst.type == Shader::PARAMETER_OUTPUT) | 
|  | { | 
|  | unsigned char usage = inst->usage; | 
|  | unsigned char usageIndex = inst->usageIndex; | 
|  |  | 
|  | const DestinationParameter &dst = inst->dst; | 
|  |  | 
|  | if(dst.x) output[dst.index][0] = Semantic(usage, usageIndex); | 
|  | if(dst.y) output[dst.index][1] = Semantic(usage, usageIndex); | 
|  | if(dst.z) output[dst.index][2] = Semantic(usage, usageIndex); | 
|  | if(dst.w) output[dst.index][3] = Semantic(usage, usageIndex); | 
|  |  | 
|  | if(usage == Shader::USAGE_POSITION && usageIndex == 0) | 
|  | { | 
|  | positionRegister = dst.index; | 
|  | } | 
|  |  | 
|  | if(usage == Shader::USAGE_PSIZE && usageIndex == 0) | 
|  | { | 
|  | pointSizeRegister = dst.index; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void VertexShader::analyzeTextureSampling() | 
|  | { | 
|  | textureSampling = false; | 
|  |  | 
|  | for(const auto &inst : instruction) | 
|  | { | 
|  | if(inst->src[1].type == PARAMETER_SAMPLER) | 
|  | { | 
|  | textureSampling = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } |