Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 1 | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #ifndef COMPILER_OUTPUTASM_H_ |
| 16 | #define COMPILER_OUTPUTASM_H_ |
| 17 | |
| 18 | #include "intermediate.h" |
| 19 | #include "ParseHelper.h" |
| 20 | #include "Shader/PixelShader.hpp" |
| 21 | #include "Shader/VertexShader.hpp" |
| 22 | |
| 23 | #include <list> |
| 24 | #include <set> |
| 25 | #include <map> |
| 26 | |
| 27 | namespace es2 |
| 28 | { |
| 29 | class Shader; |
| 30 | } |
| 31 | |
| 32 | typedef unsigned int GLenum; |
| 33 | |
| 34 | namespace glsl |
| 35 | { |
| 36 | struct BlockMemberInfo |
| 37 | { |
| 38 | BlockMemberInfo() : offset(-1), arrayStride(-1), matrixStride(-1), isRowMajorMatrix(false) {} |
| 39 | |
| 40 | BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix) |
| 41 | : offset(offset), |
| 42 | arrayStride(arrayStride), |
| 43 | matrixStride(matrixStride), |
| 44 | isRowMajorMatrix(isRowMajorMatrix) |
| 45 | {} |
| 46 | |
| 47 | static BlockMemberInfo getDefaultBlockInfo() |
| 48 | { |
| 49 | return BlockMemberInfo(-1, -1, -1, false); |
| 50 | } |
| 51 | |
| 52 | int offset; |
| 53 | int arrayStride; |
| 54 | int matrixStride; |
| 55 | bool isRowMajorMatrix; |
| 56 | }; |
| 57 | |
| 58 | struct Uniform |
| 59 | { |
| 60 | Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo); |
| 61 | |
| 62 | GLenum type; |
| 63 | GLenum precision; |
| 64 | std::string name; |
| 65 | int arraySize; |
| 66 | |
| 67 | int registerIndex; |
| 68 | |
| 69 | int blockId; |
| 70 | BlockMemberInfo blockInfo; |
| 71 | }; |
| 72 | |
| 73 | typedef std::vector<Uniform> ActiveUniforms; |
| 74 | |
| 75 | struct UniformBlock |
| 76 | { |
| 77 | UniformBlock(const std::string& name, unsigned int dataSize, unsigned int arraySize, |
| 78 | TLayoutBlockStorage layout, bool isRowMajorLayout, int registerIndex, int blockId); |
| 79 | |
| 80 | std::string name; |
| 81 | unsigned int dataSize; |
| 82 | unsigned int arraySize; |
| 83 | TLayoutBlockStorage layout; |
| 84 | bool isRowMajorLayout; |
| 85 | std::vector<int> fields; |
| 86 | |
| 87 | int registerIndex; |
| 88 | |
| 89 | int blockId; |
| 90 | }; |
| 91 | |
| 92 | class BlockLayoutEncoder |
| 93 | { |
| 94 | public: |
| 95 | BlockLayoutEncoder(bool rowMajor); |
| 96 | virtual ~BlockLayoutEncoder() {} |
| 97 | |
| 98 | BlockMemberInfo encodeType(const TType &type); |
| 99 | |
| 100 | size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; } |
| 101 | |
| 102 | virtual void enterAggregateType() = 0; |
| 103 | virtual void exitAggregateType() = 0; |
| 104 | |
| 105 | static const size_t BytesPerComponent = 4u; |
| 106 | static const unsigned int ComponentsPerRegister = 4u; |
| 107 | |
| 108 | static size_t getBlockRegister(const BlockMemberInfo &info); |
| 109 | static size_t getBlockRegisterElement(const BlockMemberInfo &info); |
| 110 | |
| 111 | protected: |
| 112 | size_t mCurrentOffset; |
| 113 | bool isRowMajor; |
| 114 | |
| 115 | void nextRegister(); |
| 116 | |
| 117 | virtual void getBlockLayoutInfo(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) = 0; |
| 118 | virtual void advanceOffset(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) = 0; |
| 119 | }; |
| 120 | |
| 121 | // Block layout according to the std140 block layout |
| 122 | // See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification |
| 123 | class Std140BlockEncoder : public BlockLayoutEncoder |
| 124 | { |
| 125 | public: |
| 126 | Std140BlockEncoder(bool rowMajor); |
| 127 | |
| 128 | void enterAggregateType() override; |
| 129 | void exitAggregateType() override; |
| 130 | |
| 131 | protected: |
| 132 | void getBlockLayoutInfo(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) override; |
| 133 | void advanceOffset(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) override; |
| 134 | }; |
| 135 | |
| 136 | typedef std::vector<UniformBlock> ActiveUniformBlocks; |
| 137 | |
| 138 | struct Attribute |
| 139 | { |
| 140 | Attribute(); |
| 141 | Attribute(GLenum type, const std::string &name, int arraySize, int location, int registerIndex); |
| 142 | |
| 143 | GLenum type; |
| 144 | std::string name; |
| 145 | int arraySize; |
| 146 | int location; |
| 147 | |
| 148 | int registerIndex; |
| 149 | }; |
| 150 | |
| 151 | typedef std::vector<Attribute> ActiveAttributes; |
| 152 | |
| 153 | struct Varying |
| 154 | { |
| 155 | Varying(GLenum type, const std::string &name, int arraySize, int reg = -1, int col = -1) |
| 156 | : type(type), name(name), arraySize(arraySize), reg(reg), col(col) |
| 157 | { |
| 158 | } |
| 159 | |
| 160 | bool isArray() const |
| 161 | { |
| 162 | return arraySize >= 1; |
| 163 | } |
| 164 | |
| 165 | int size() const // Unify with es2::Uniform? |
| 166 | { |
| 167 | return arraySize > 0 ? arraySize : 1; |
| 168 | } |
| 169 | |
| 170 | GLenum type; |
| 171 | std::string name; |
| 172 | int arraySize; |
| 173 | |
| 174 | int reg; // First varying register, assigned during link |
| 175 | int col; // First register element, assigned during link |
| 176 | }; |
| 177 | |
| 178 | typedef std::list<Varying> VaryingList; |
| 179 | |
| 180 | class Shader |
| 181 | { |
| 182 | friend class OutputASM; |
| 183 | public: |
| 184 | virtual ~Shader() {}; |
| 185 | virtual sw::Shader *getShader() const = 0; |
| 186 | virtual sw::PixelShader *getPixelShader() const; |
| 187 | virtual sw::VertexShader *getVertexShader() const; |
| 188 | |
| 189 | protected: |
| 190 | VaryingList varyings; |
| 191 | ActiveUniforms activeUniforms; |
| 192 | ActiveAttributes activeAttributes; |
| 193 | ActiveUniformBlocks activeUniformBlocks; |
| 194 | }; |
| 195 | |
| 196 | struct Function |
| 197 | { |
| 198 | Function(int label, const char *name, TIntermSequence *arg, TIntermTyped *ret) : label(label), name(name), arg(arg), ret(ret) |
| 199 | { |
| 200 | } |
| 201 | |
| 202 | Function(int label, const TString &name, TIntermSequence *arg, TIntermTyped *ret) : label(label), name(name), arg(arg), ret(ret) |
| 203 | { |
| 204 | } |
| 205 | |
| 206 | int label; |
| 207 | TString name; |
| 208 | TIntermSequence *arg; |
| 209 | TIntermTyped *ret; |
| 210 | }; |
| 211 | |
| 212 | typedef sw::Shader::Instruction Instruction; |
| 213 | |
| 214 | class Temporary; |
| 215 | |
| 216 | class OutputASM : public TIntermTraverser |
| 217 | { |
| 218 | public: |
| 219 | explicit OutputASM(TParseContext &context, Shader *shaderObject); |
| 220 | ~OutputASM(); |
| 221 | |
| 222 | void output(); |
| 223 | |
| 224 | void freeTemporary(Temporary *temporary); |
| 225 | |
| 226 | private: |
| 227 | enum Scope |
| 228 | { |
| 229 | GLOBAL, |
| 230 | FUNCTION |
| 231 | }; |
| 232 | |
| 233 | struct TextureFunction |
| 234 | { |
| 235 | TextureFunction(const TString& name); |
| 236 | |
| 237 | enum Method |
| 238 | { |
| 239 | IMPLICIT, // Mipmap LOD determined implicitly (standard lookup) |
| 240 | LOD, |
| 241 | SIZE, // textureSize() |
| 242 | FETCH, |
| 243 | GRAD |
| 244 | }; |
| 245 | |
| 246 | Method method; |
| 247 | bool proj; |
| 248 | bool offset; |
| 249 | }; |
| 250 | |
| 251 | void emitShader(Scope scope); |
| 252 | |
| 253 | // Visit AST nodes and output their code to the body stream |
Nicolas Capens | 0530b45 | 2017-11-15 16:39:47 -0500 | [diff] [blame] | 254 | void visitSymbol(TIntermSymbol*) override; |
| 255 | bool visitBinary(Visit visit, TIntermBinary*) override; |
| 256 | bool visitUnary(Visit visit, TIntermUnary*) override; |
| 257 | bool visitSelection(Visit visit, TIntermSelection*) override; |
| 258 | bool visitAggregate(Visit visit, TIntermAggregate*) override; |
| 259 | bool visitLoop(Visit visit, TIntermLoop*) override; |
| 260 | bool visitBranch(Visit visit, TIntermBranch*) override; |
| 261 | bool visitSwitch(Visit, TIntermSwitch*) override; |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 262 | |
| 263 | sw::Shader::Opcode getOpcode(sw::Shader::Opcode op, TIntermTyped *in) const; |
| 264 | Instruction *emit(sw::Shader::Opcode op, TIntermTyped *dst = 0, TIntermNode *src0 = 0, TIntermNode *src1 = 0, TIntermNode *src2 = 0, TIntermNode *src3 = 0, TIntermNode *src4 = 0); |
| 265 | Instruction *emit(sw::Shader::Opcode op, TIntermTyped *dst, int dstIndex, TIntermNode *src0 = 0, int index0 = 0, TIntermNode *src1 = 0, int index1 = 0, |
| 266 | TIntermNode *src2 = 0, int index2 = 0, TIntermNode *src3 = 0, int index3 = 0, TIntermNode *src4 = 0, int index4 = 0); |
| 267 | Instruction *emitCast(TIntermTyped *dst, TIntermTyped *src); |
| 268 | Instruction *emitCast(TIntermTyped *dst, int dstIndex, TIntermTyped *src, int srcIndex); |
| 269 | void emitBinary(sw::Shader::Opcode op, TIntermTyped *dst = 0, TIntermNode *src0 = 0, TIntermNode *src1 = 0, TIntermNode *src2 = 0); |
| 270 | void emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1 = 0); |
| 271 | void emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index = 0); |
| 272 | void emitDeterminant(TIntermTyped *result, TIntermTyped *arg, int size, int col = -1, int row = -1, int outCol = 0, int outRow = 0); |
Nicolas Capens | 0530b45 | 2017-11-15 16:39:47 -0500 | [diff] [blame] | 273 | void source(sw::Shader::SourceParameter ¶meter, TIntermNode *argument, int index = 0); |
| 274 | void destination(sw::Shader::DestinationParameter ¶meter, TIntermTyped *argument, int index = 0); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 275 | void copy(TIntermTyped *dst, TIntermNode *src, int offset = 0); |
| 276 | void assignLvalue(TIntermTyped *dst, TIntermTyped *src); |
Nicolas Capens | d469de2 | 2017-11-16 10:42:20 -0500 | [diff] [blame] | 277 | void evaluateRvalue(TIntermTyped *node); |
Nicolas Capens | 6986b28 | 2017-11-16 10:38:19 -0500 | [diff] [blame] | 278 | int lvalue(sw::Shader::DestinationParameter &dst, TIntermTyped *node); |
Nicolas Capens | 0530b45 | 2017-11-15 16:39:47 -0500 | [diff] [blame] | 279 | int lvalue(TIntermTyped *&root, unsigned int &offset, sw::Shader::Relative &rel, unsigned char &mask, Temporary &address, TIntermTyped *node); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 280 | sw::Shader::ParameterType registerType(TIntermTyped *operand); |
Alexis Hetu | 12b0050 | 2016-05-20 13:01:11 -0400 | [diff] [blame] | 281 | bool hasFlatQualifier(TIntermTyped *operand); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 282 | unsigned int registerIndex(TIntermTyped *operand); |
| 283 | int writeMask(TIntermTyped *destination, int index = 0); |
| 284 | int readSwizzle(TIntermTyped *argument, int size); |
| 285 | bool trivial(TIntermTyped *expression, int budget); // Fast to compute and no side effects |
| 286 | int cost(TIntermNode *expression, int budget); |
| 287 | const Function *findFunction(const TString &name); |
| 288 | |
| 289 | int temporaryRegister(TIntermTyped *temporary); |
| 290 | int varyingRegister(TIntermTyped *varying); |
Alexis Hetu | 4935123 | 2017-11-02 16:00:32 -0400 | [diff] [blame] | 291 | void setPixelShaderInputs(const TType& type, int var, bool flat); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 292 | void declareVarying(TIntermTyped *varying, int reg); |
Alexis Hetu | 4935123 | 2017-11-02 16:00:32 -0400 | [diff] [blame] | 293 | void declareVarying(const TType &type, const TString &name, int registerIndex); |
Nicolas Capens | 0bac285 | 2016-05-07 06:09:58 -0400 | [diff] [blame] | 294 | int uniformRegister(TIntermTyped *uniform); |
| 295 | int attributeRegister(TIntermTyped *attribute); |
| 296 | int fragmentOutputRegister(TIntermTyped *fragmentOutput); |
| 297 | int samplerRegister(TIntermTyped *sampler); |
| 298 | int samplerRegister(TIntermSymbol *sampler); |
| 299 | bool isSamplerRegister(TIntermTyped *operand); |
| 300 | |
| 301 | typedef std::vector<TIntermTyped*> VariableArray; |
| 302 | |
| 303 | int lookup(VariableArray &list, TIntermTyped *variable); |
| 304 | int lookup(VariableArray &list, TInterfaceBlock *block); |
| 305 | int blockMemberLookup(const TType &type, const TString &name, int registerIndex); |
| 306 | int allocate(VariableArray &list, TIntermTyped *variable); |
| 307 | void free(VariableArray &list, TIntermTyped *variable); |
| 308 | |
| 309 | void declareUniform(const TType &type, const TString &name, int registerIndex, int blockId = -1, BlockLayoutEncoder* encoder = nullptr); |
| 310 | GLenum glVariableType(const TType &type); |
| 311 | GLenum glVariablePrecision(const TType &type); |
| 312 | |
| 313 | static int dim(TIntermNode *v); |
| 314 | static int dim2(TIntermNode *m); |
| 315 | static unsigned int loopCount(TIntermLoop *node); |
| 316 | |
| 317 | Shader *const shaderObject; |
| 318 | sw::Shader *shader; |
| 319 | sw::PixelShader *pixelShader; |
| 320 | sw::VertexShader *vertexShader; |
| 321 | |
| 322 | VariableArray temporaries; |
| 323 | VariableArray uniforms; |
| 324 | VariableArray varyings; |
| 325 | VariableArray attributes; |
| 326 | VariableArray samplers; |
| 327 | VariableArray fragmentOutputs; |
| 328 | |
| 329 | struct TypedMemberInfo : public BlockMemberInfo |
| 330 | { |
| 331 | TypedMemberInfo() {} |
| 332 | TypedMemberInfo(const BlockMemberInfo& b, const TType& t) : BlockMemberInfo(b), type(t) {} |
| 333 | TType type; |
| 334 | }; |
| 335 | struct ArgumentInfo |
| 336 | { |
| 337 | ArgumentInfo(const BlockMemberInfo& b, const TType& t, int clampedIndex, int bufferIndex) : |
| 338 | typedMemberInfo(b, t), clampedIndex(clampedIndex), bufferIndex(bufferIndex) {} |
| 339 | TypedMemberInfo typedMemberInfo; |
| 340 | int clampedIndex; |
| 341 | int bufferIndex; |
| 342 | }; |
| 343 | int getBlockId(TIntermTyped *argument); |
| 344 | ArgumentInfo getArgumentInfo(TIntermTyped *argument, int index); |
| 345 | |
| 346 | typedef std::map<int, TypedMemberInfo> BlockDefinitionIndexMap; |
| 347 | std::vector<BlockDefinitionIndexMap> blockDefinitions; |
| 348 | |
| 349 | Scope emitScope; |
| 350 | Scope currentScope; |
| 351 | |
| 352 | int currentFunction; |
| 353 | std::vector<Function> functionArray; |
| 354 | |
| 355 | TQualifier outputQualifier; |
| 356 | |
| 357 | TParseContext &mContext; |
| 358 | }; |
| 359 | |
| 360 | class LoopUnrollable : public TIntermTraverser |
| 361 | { |
| 362 | public: |
| 363 | bool traverse(TIntermNode *node); |
| 364 | |
| 365 | private: |
| 366 | bool visitBranch(Visit visit, TIntermBranch *node); |
| 367 | bool visitLoop(Visit visit, TIntermLoop *loop); |
| 368 | bool visitAggregate(Visit visit, TIntermAggregate *node); |
| 369 | |
| 370 | int loopDepth; |
| 371 | bool loopUnrollable; |
| 372 | }; |
| 373 | } |
| 374 | |
| 375 | #endif // COMPILER_OUTPUTASM_H_ |