// 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 COMPILER_OUTPUTASM_H_ #define COMPILER_OUTPUTASM_H_ #include "intermediate.h" #include "ParseHelper.h" #include "Shader/PixelShader.hpp" #include "Shader/VertexShader.hpp" #include <list> #include <set> #include <map> namespace es2 { class Shader; } typedef unsigned int GLenum; namespace glsl { struct BlockMemberInfo { BlockMemberInfo() : offset(-1), arrayStride(-1), matrixStride(-1), isRowMajorMatrix(false) {} BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix) : offset(offset), arrayStride(arrayStride), matrixStride(matrixStride), isRowMajorMatrix(isRowMajorMatrix) {} static BlockMemberInfo getDefaultBlockInfo() { return BlockMemberInfo(-1, -1, -1, false); } int offset; int arrayStride; int matrixStride; bool isRowMajorMatrix; }; struct ShaderVariable { ShaderVariable(const TType& type, const std::string& name, int registerIndex); GLenum type; GLenum precision; std::string name; int arraySize; int registerIndex; std::vector<ShaderVariable> fields; }; struct Uniform : public ShaderVariable { Uniform(const TType& type, const std::string &name, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo); int blockId; BlockMemberInfo blockInfo; }; typedef std::vector<Uniform> ActiveUniforms; struct UniformBlock { UniformBlock(const std::string& name, unsigned int dataSize, unsigned int arraySize, TLayoutBlockStorage layout, bool isRowMajorLayout, int registerIndex, int blockId); std::string name; unsigned int dataSize; unsigned int arraySize; TLayoutBlockStorage layout; bool isRowMajorLayout; std::vector<int> fields; int registerIndex; int blockId; }; class BlockLayoutEncoder { public: BlockLayoutEncoder(); virtual ~BlockLayoutEncoder() {} BlockMemberInfo encodeType(const TType &type); size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; } virtual void enterAggregateType() = 0; virtual void exitAggregateType() = 0; static const size_t BytesPerComponent = 4u; static const unsigned int ComponentsPerRegister = 4u; static size_t getBlockRegister(const BlockMemberInfo &info); static size_t getBlockRegisterElement(const BlockMemberInfo &info); protected: size_t mCurrentOffset; void nextRegister(); virtual void getBlockLayoutInfo(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) = 0; virtual void advanceOffset(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) = 0; }; // Block layout according to the std140 block layout // See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification class Std140BlockEncoder : public BlockLayoutEncoder { public: Std140BlockEncoder(); void enterAggregateType() override; void exitAggregateType() override; protected: void getBlockLayoutInfo(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) override; void advanceOffset(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) override; }; typedef std::vector<UniformBlock> ActiveUniformBlocks; struct Attribute { Attribute(); Attribute(GLenum type, const std::string &name, int arraySize, int location, int registerIndex); GLenum type; std::string name; int arraySize; int location; int registerIndex; }; typedef std::vector<Attribute> ActiveAttributes; struct Varying : public ShaderVariable { Varying(const TType& type, const std::string &name, int reg = -1, int col = -1) : ShaderVariable(type, name, reg), qualifier(type.getQualifier()), column(col) { } bool isArray() const { return arraySize >= 1; } int size() const // Unify with es2::Uniform? { return arraySize > 0 ? arraySize : 1; } TQualifier qualifier; int column; // First register element, assigned during link }; typedef std::list<Varying> VaryingList; class Shader { friend class OutputASM; public: virtual ~Shader() {}; virtual sw::Shader *getShader() const = 0; virtual sw::PixelShader *getPixelShader() const; virtual sw::VertexShader *getVertexShader() const; int getShaderVersion() const { return shaderVersion; } protected: VaryingList varyings; ActiveUniforms activeUniforms; ActiveUniforms activeUniformStructs; ActiveAttributes activeAttributes; ActiveUniformBlocks activeUniformBlocks; int shaderVersion; }; struct Function { Function(int label, const char *name, TIntermSequence *arg, TIntermTyped *ret) : label(label), name(name), arg(arg), ret(ret) { } Function(int label, const TString &name, TIntermSequence *arg, TIntermTyped *ret) : label(label), name(name), arg(arg), ret(ret) { } int label; TString name; TIntermSequence *arg; TIntermTyped *ret; }; typedef sw::Shader::Instruction Instruction; class Temporary; class OutputASM : public TIntermTraverser { public: explicit OutputASM(TParseContext &context, Shader *shaderObject); ~OutputASM(); void output(); void freeTemporary(Temporary *temporary); private: enum Scope { GLOBAL, FUNCTION }; struct TextureFunction { TextureFunction(const TString& name); enum Method { IMPLICIT, // Mipmap LOD determined implicitly (standard lookup) LOD, SIZE, // textureSize() FETCH, GRAD, }; Method method; bool proj; bool offset; }; void emitShader(Scope scope); // Visit AST nodes and output their code to the body stream void visitSymbol(TIntermSymbol*) override; bool visitBinary(Visit visit, TIntermBinary*) override; bool visitUnary(Visit visit, TIntermUnary*) override; bool visitSelection(Visit visit, TIntermSelection*) override; bool visitAggregate(Visit visit, TIntermAggregate*) override; bool visitLoop(Visit visit, TIntermLoop*) override; bool visitBranch(Visit visit, TIntermBranch*) override; bool visitSwitch(Visit, TIntermSwitch*) override; sw::Shader::Opcode getOpcode(sw::Shader::Opcode op, TIntermTyped *in) const; Instruction *emit(sw::Shader::Opcode op, TIntermTyped *dst = 0, TIntermNode *src0 = 0, TIntermNode *src1 = 0, TIntermNode *src2 = 0, TIntermNode *src3 = 0, TIntermNode *src4 = 0); Instruction *emit(sw::Shader::Opcode op, TIntermTyped *dst, int dstIndex, TIntermNode *src0 = 0, int index0 = 0, TIntermNode *src1 = 0, int index1 = 0, TIntermNode *src2 = 0, int index2 = 0, TIntermNode *src3 = 0, int index3 = 0, TIntermNode *src4 = 0, int index4 = 0); Instruction *emitCast(TIntermTyped *dst, TIntermTyped *src); Instruction *emitCast(TIntermTyped *dst, int dstIndex, TIntermTyped *src, int srcIndex); void emitBinary(sw::Shader::Opcode op, TIntermTyped *dst = 0, TIntermNode *src0 = 0, TIntermNode *src1 = 0, TIntermNode *src2 = 0); void emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1 = 0); void emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index = 0); void emitDeterminant(TIntermTyped *result, TIntermTyped *arg, int size, int col = -1, int row = -1, int outCol = 0, int outRow = 0); void source(sw::Shader::SourceParameter ¶meter, TIntermNode *argument, int index = 0); void destination(sw::Shader::DestinationParameter ¶meter, TIntermTyped *argument, int index = 0); void copy(TIntermTyped *dst, TIntermNode *src, int offset = 0); void assignLvalue(TIntermTyped *dst, TIntermTyped *src); void evaluateRvalue(TIntermTyped *node); int lvalue(sw::Shader::DestinationParameter &dst, TIntermTyped *node); int lvalue(TIntermTyped *&root, unsigned int &offset, sw::Shader::Relative &rel, unsigned char &mask, Temporary &address, TIntermTyped *node); sw::Shader::ParameterType registerType(TIntermTyped *operand); bool hasFlatQualifier(TIntermTyped *operand); unsigned int registerIndex(TIntermTyped *operand); int writeMask(TIntermTyped *destination, int index = 0); int readSwizzle(TIntermTyped *argument, int size); bool trivial(TIntermTyped *expression, int budget); // Fast to compute and no side effects int cost(TIntermNode *expression, int budget); const Function *findFunction(const TString &name); int temporaryRegister(TIntermTyped *temporary); int varyingRegister(TIntermTyped *varying); void setPixelShaderInputs(const TType& type, int var, bool flat); void declareVarying(TIntermTyped *varying, int reg); void declareVarying(const TType &type, const TString &name, int registerIndex); void declareFragmentOutput(TIntermTyped *fragmentOutput); int uniformRegister(TIntermTyped *uniform); int attributeRegister(TIntermTyped *attribute); int fragmentOutputRegister(TIntermTyped *fragmentOutput); int samplerRegister(TIntermTyped *sampler); int samplerRegister(TIntermSymbol *sampler); bool isSamplerRegister(TIntermTyped *operand); typedef std::vector<TIntermTyped*> VariableArray; int lookup(VariableArray &list, TIntermTyped *variable); int lookup(VariableArray &list, TInterfaceBlock *block); int blockMemberLookup(const TType &type, const TString &name, int registerIndex); int allocate(VariableArray &list, TIntermTyped *variable, bool samplersOnly = false); void free(VariableArray &list, TIntermTyped *variable); void declareUniform(const TType &type, const TString &name, int registerIndex, bool samplersOnly, int blockId = -1, BlockLayoutEncoder* encoder = nullptr); static int dim(TIntermNode *v); static int dim2(TIntermNode *m); static unsigned int loopCount(TIntermLoop *node); Shader *const shaderObject; sw::Shader *shader; sw::PixelShader *pixelShader; sw::VertexShader *vertexShader; VariableArray temporaries; VariableArray uniforms; VariableArray varyings; VariableArray attributes; VariableArray samplers; VariableArray fragmentOutputs; struct TypedMemberInfo : public BlockMemberInfo { TypedMemberInfo(const BlockMemberInfo& b, const TType& t) : BlockMemberInfo(b), type(t) {} TType type; }; struct ArgumentInfo { ArgumentInfo(const BlockMemberInfo& b, const TType& t, int clampedIndex, int bufferIndex) : typedMemberInfo(b, t), clampedIndex(clampedIndex), bufferIndex(bufferIndex) {} TypedMemberInfo typedMemberInfo; int clampedIndex; int bufferIndex; }; int getBlockId(TIntermTyped *argument); ArgumentInfo getArgumentInfo(TIntermTyped *argument, int index); typedef std::map<int, TypedMemberInfo> BlockDefinitionIndexMap; std::vector<BlockDefinitionIndexMap> blockDefinitions; Scope emitScope; Scope currentScope; int currentFunction; std::vector<Function> functionArray; TQualifier outputQualifier; TParseContext &mContext; }; class LoopUnrollable : public TIntermTraverser { public: bool traverse(TIntermNode *node); private: bool visitBranch(Visit visit, TIntermBranch *node); bool visitLoop(Visit visit, TIntermLoop *loop); bool visitAggregate(Visit visit, TIntermAggregate *node); int loopDepth; bool loopUnrollable; }; } #endif // COMPILER_OUTPUTASM_H_