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 ShaderVariable |
59 | { |
60 | ShaderVariable(const TType& type, const std::string& name, int registerIndex); |
61 | |
62 | GLenum type; |
63 | GLenum precision; |
64 | std::string name; |
65 | int arraySize; |
66 | |
67 | int registerIndex; |
68 | |
69 | std::vector<ShaderVariable> fields; |
70 | }; |
71 | |
72 | struct Uniform : public ShaderVariable |
73 | { |
74 | Uniform(const TType& type, const std::string &name, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo); |
75 | |
76 | int blockId; |
77 | BlockMemberInfo blockInfo; |
78 | }; |
79 | |
80 | typedef std::vector<Uniform> ActiveUniforms; |
81 | |
82 | struct UniformBlock |
83 | { |
84 | UniformBlock(const std::string& name, unsigned int dataSize, unsigned int arraySize, |
85 | TLayoutBlockStorage layout, bool isRowMajorLayout, int registerIndex, int blockId); |
86 | |
87 | std::string name; |
88 | unsigned int dataSize; |
89 | unsigned int arraySize; |
90 | TLayoutBlockStorage layout; |
91 | bool isRowMajorLayout; |
92 | std::vector<int> fields; |
93 | |
94 | int registerIndex; |
95 | |
96 | int blockId; |
97 | }; |
98 | |
99 | class BlockLayoutEncoder |
100 | { |
101 | public: |
102 | BlockLayoutEncoder(); |
103 | virtual ~BlockLayoutEncoder() {} |
104 | |
105 | BlockMemberInfo encodeType(const TType &type); |
106 | |
107 | size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; } |
108 | |
109 | virtual void enterAggregateType() = 0; |
110 | virtual void exitAggregateType() = 0; |
111 | |
112 | static const size_t BytesPerComponent = 4u; |
113 | static const unsigned int ComponentsPerRegister = 4u; |
114 | |
115 | static size_t getBlockRegister(const BlockMemberInfo &info); |
116 | static size_t getBlockRegisterElement(const BlockMemberInfo &info); |
117 | |
118 | protected: |
119 | size_t mCurrentOffset; |
120 | |
121 | void nextRegister(); |
122 | |
123 | virtual void getBlockLayoutInfo(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) = 0; |
124 | virtual void advanceOffset(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) = 0; |
125 | }; |
126 | |
127 | // Block layout according to the std140 block layout |
128 | // See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification |
129 | class Std140BlockEncoder : public BlockLayoutEncoder |
130 | { |
131 | public: |
132 | Std140BlockEncoder(); |
133 | |
134 | void enterAggregateType() override; |
135 | void exitAggregateType() override; |
136 | |
137 | protected: |
138 | void getBlockLayoutInfo(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) override; |
139 | void advanceOffset(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) override; |
140 | }; |
141 | |
142 | typedef std::vector<UniformBlock> ActiveUniformBlocks; |
143 | |
144 | struct Attribute |
145 | { |
146 | Attribute(); |
147 | Attribute(GLenum type, const std::string &name, int arraySize, int layoutLocation, int registerIndex); |
148 | |
149 | GLenum type; |
150 | std::string name; |
151 | int arraySize; |
152 | int layoutLocation; |
153 | |
154 | int registerIndex; |
155 | }; |
156 | |
157 | typedef std::vector<Attribute> ActiveAttributes; |
158 | |
159 | struct Varying : public ShaderVariable |
160 | { |
161 | Varying(const TType& type, const std::string &name, int reg = -1, int col = -1) |
162 | : ShaderVariable(type, name, reg), qualifier(type.getQualifier()), column(col) |
163 | { |
164 | } |
165 | |
166 | bool isArray() const |
167 | { |
168 | return arraySize >= 1; |
169 | } |
170 | |
171 | int size() const // Unify with es2::Uniform? |
172 | { |
173 | return arraySize > 0 ? arraySize : 1; |
174 | } |
175 | |
176 | TQualifier qualifier; |
177 | int column; // First register element, assigned during link |
178 | }; |
179 | |
180 | typedef std::list<Varying> VaryingList; |
181 | |
182 | class Shader |
183 | { |
184 | friend class OutputASM; |
185 | public: |
186 | virtual ~Shader() {} |
187 | virtual sw::Shader *getShader() const = 0; |
188 | virtual sw::PixelShader *getPixelShader() const; |
189 | virtual sw::VertexShader *getVertexShader() const; |
190 | int getShaderVersion() const { return shaderVersion; } |
191 | |
192 | protected: |
193 | VaryingList varyings; |
194 | ActiveUniforms activeUniforms; |
195 | ActiveUniforms activeUniformStructs; |
196 | ActiveAttributes activeAttributes; |
197 | ActiveUniformBlocks activeUniformBlocks; |
198 | int shaderVersion; |
199 | }; |
200 | |
201 | struct Function |
202 | { |
203 | Function(int label, const char *name, TIntermSequence *arg, TIntermTyped *ret) : label(label), name(name), arg(arg), ret(ret) |
204 | { |
205 | } |
206 | |
207 | Function(int label, const TString &name, TIntermSequence *arg, TIntermTyped *ret) : label(label), name(name), arg(arg), ret(ret) |
208 | { |
209 | } |
210 | |
211 | int label; |
212 | TString name; |
213 | TIntermSequence *arg; |
214 | TIntermTyped *ret; |
215 | }; |
216 | |
217 | typedef sw::Shader::Instruction Instruction; |
218 | |
219 | class Temporary; |
220 | |
221 | class OutputASM : public TIntermTraverser |
222 | { |
223 | public: |
224 | explicit OutputASM(TParseContext &context, Shader *shaderObject); |
225 | ~OutputASM(); |
226 | |
227 | void output(); |
228 | |
229 | void freeTemporary(Temporary *temporary); |
230 | |
231 | private: |
232 | enum Scope |
233 | { |
234 | GLOBAL, |
235 | FUNCTION |
236 | }; |
237 | |
238 | struct TextureFunction |
239 | { |
240 | TextureFunction(const TString& name); |
241 | |
242 | enum Method |
243 | { |
244 | IMPLICIT, // Mipmap LOD determined implicitly (standard lookup) |
245 | LOD, |
246 | SIZE, // textureSize() |
247 | FETCH, |
248 | GRAD, |
249 | }; |
250 | |
251 | Method method; |
252 | bool proj; |
253 | bool offset; |
254 | }; |
255 | |
256 | void emitShader(Scope scope); |
257 | |
258 | // Visit AST nodes and output their code to the body stream |
259 | void visitSymbol(TIntermSymbol*) override; |
260 | bool visitBinary(Visit visit, TIntermBinary*) override; |
261 | bool visitUnary(Visit visit, TIntermUnary*) override; |
262 | bool visitSelection(Visit visit, TIntermSelection*) override; |
263 | bool visitAggregate(Visit visit, TIntermAggregate*) override; |
264 | bool visitLoop(Visit visit, TIntermLoop*) override; |
265 | bool visitBranch(Visit visit, TIntermBranch*) override; |
266 | bool visitSwitch(Visit, TIntermSwitch*) override; |
267 | |
268 | sw::Shader::Opcode getOpcode(sw::Shader::Opcode op, TIntermTyped *in) const; |
269 | Instruction *emit(sw::Shader::Opcode op, TIntermTyped *dst = 0, TIntermNode *src0 = 0, TIntermNode *src1 = 0, TIntermNode *src2 = 0, TIntermNode *src3 = 0, TIntermNode *src4 = 0); |
270 | Instruction *emit(sw::Shader::Opcode op, TIntermTyped *dst, int dstIndex, TIntermNode *src0 = 0, int index0 = 0, TIntermNode *src1 = 0, int index1 = 0, |
271 | TIntermNode *src2 = 0, int index2 = 0, TIntermNode *src3 = 0, int index3 = 0, TIntermNode *src4 = 0, int index4 = 0); |
272 | Instruction *emitCast(TIntermTyped *dst, TIntermTyped *src); |
273 | Instruction *emitCast(TIntermTyped *dst, int dstIndex, TIntermTyped *src, int srcIndex); |
274 | void emitBinary(sw::Shader::Opcode op, TIntermTyped *dst = 0, TIntermNode *src0 = 0, TIntermNode *src1 = 0, TIntermNode *src2 = 0); |
275 | void emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1 = 0); |
276 | void emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index = 0); |
277 | void emitDeterminant(TIntermTyped *result, TIntermTyped *arg, int size, int col = -1, int row = -1, int outCol = 0, int outRow = 0); |
278 | void source(sw::Shader::SourceParameter ¶meter, TIntermNode *argument, int index = 0); |
279 | void destination(sw::Shader::DestinationParameter ¶meter, TIntermTyped *argument, int index = 0); |
280 | void copy(TIntermTyped *dst, TIntermNode *src, int offset = 0); |
281 | void assignLvalue(TIntermTyped *dst, TIntermTyped *src); |
282 | void evaluateRvalue(TIntermTyped *node); |
283 | int lvalue(sw::Shader::DestinationParameter &dst, TIntermTyped *node); |
284 | int lvalue(TIntermTyped *&root, unsigned int &offset, sw::Shader::Relative &rel, unsigned char &mask, Temporary &address, TIntermTyped *node); |
285 | sw::Shader::ParameterType registerType(TIntermTyped *operand); |
286 | bool hasFlatQualifier(TIntermTyped *operand); |
287 | unsigned int registerIndex(TIntermTyped *operand); |
288 | int writeMask(TIntermTyped *destination, int index = 0); |
289 | int readSwizzle(TIntermTyped *argument, int size); |
290 | bool trivial(TIntermTyped *expression, int budget); // Fast to compute and no side effects |
291 | int cost(TIntermNode *expression, int budget); |
292 | const Function *findFunction(const TString &name); |
293 | |
294 | int temporaryRegister(TIntermTyped *temporary); |
295 | int varyingRegister(TIntermTyped *varying); |
296 | void setPixelShaderInputs(const TType& type, int var, bool flat); |
297 | void declareVarying(TIntermTyped *varying, int reg); |
298 | void declareVarying(const TType &type, const TString &name, int registerIndex); |
299 | void declareFragmentOutput(TIntermTyped *fragmentOutput); |
300 | int uniformRegister(TIntermTyped *uniform); |
301 | int attributeRegister(TIntermTyped *attribute); |
302 | int fragmentOutputRegister(TIntermTyped *fragmentOutput); |
303 | int samplerRegister(TIntermTyped *sampler); |
304 | int samplerRegister(TIntermSymbol *sampler); |
305 | bool isSamplerRegister(TIntermTyped *operand); |
306 | bool arrayExceedsLimits(TIntermTyped *operand); |
307 | |
308 | typedef std::vector<TIntermTyped*> VariableArray; |
309 | |
310 | int lookup(VariableArray &list, TIntermTyped *variable); |
311 | int lookup(VariableArray &list, TInterfaceBlock *block); |
312 | int blockMemberLookup(const TType &type, const TString &name, int registerIndex); |
313 | // Returns -1 if it fails to allocate variable. |
314 | int allocate(VariableArray &list, TIntermTyped *variable, bool samplersOnly = false); |
315 | void free(VariableArray &list, TIntermTyped *variable); |
316 | |
317 | void declareUniform(const TType &type, const TString &name, int registerIndex, bool samplersOnly, int blockId = -1, BlockLayoutEncoder* encoder = nullptr); |
318 | |
319 | static int dim(TIntermNode *v); |
320 | static int dim2(TIntermNode *m); |
321 | |
322 | struct LoopInfo |
323 | { |
324 | LoopInfo(TIntermLoop *node); |
325 | |
326 | bool isDeterministic() |
327 | { |
328 | return (iterations != ~0u); |
329 | } |
330 | |
331 | unsigned int iterations = ~0u; |
332 | |
333 | TIntermSymbol *index = nullptr; |
334 | TOperator comparator = EOpNull; |
335 | int initial = 0; |
336 | int limit = 0; |
337 | int increment = 0; |
338 | }; |
339 | |
340 | Shader *const shaderObject; |
341 | sw::Shader *shader; |
342 | sw::PixelShader *pixelShader; |
343 | sw::VertexShader *vertexShader; |
344 | |
345 | VariableArray temporaries; |
346 | VariableArray uniforms; |
347 | VariableArray varyings; |
348 | VariableArray attributes; |
349 | VariableArray samplers; |
350 | VariableArray fragmentOutputs; |
351 | |
352 | struct TypedMemberInfo : public BlockMemberInfo |
353 | { |
354 | TypedMemberInfo(const BlockMemberInfo& b, const TType& t) : BlockMemberInfo(b), type(t) {} |
355 | TType type; |
356 | }; |
357 | struct ArgumentInfo |
358 | { |
359 | ArgumentInfo(const BlockMemberInfo& b, const TType& t, int clampedIndex, int bufferIndex) : |
360 | typedMemberInfo(b, t), clampedIndex(clampedIndex), bufferIndex(bufferIndex) {} |
361 | TypedMemberInfo typedMemberInfo; |
362 | int clampedIndex; |
363 | int bufferIndex; |
364 | }; |
365 | int getBlockId(TIntermTyped *argument); |
366 | ArgumentInfo getArgumentInfo(TIntermTyped *argument, int index); |
367 | |
368 | typedef std::map<int, TypedMemberInfo> BlockDefinitionIndexMap; |
369 | std::vector<BlockDefinitionIndexMap> blockDefinitions; |
370 | |
371 | Scope emitScope; |
372 | Scope currentScope; |
373 | |
374 | int currentFunction; |
375 | std::vector<Function> functionArray; |
376 | |
377 | TQualifier outputQualifier; |
378 | |
379 | std::set<int> deterministicVariables; |
380 | |
381 | TParseContext &mContext; |
382 | }; |
383 | |
384 | class LoopUnrollable : public TIntermTraverser |
385 | { |
386 | public: |
387 | bool traverse(TIntermLoop *loop, int loopIndexId); |
388 | |
389 | private: |
390 | void visitSymbol(TIntermSymbol *node) override; |
391 | bool visitBinary(Visit visit, TIntermBinary *node) override; |
392 | bool visitUnary(Visit visit, TIntermUnary *node) override; |
393 | bool visitBranch(Visit visit, TIntermBranch *node) override; |
394 | bool visitAggregate(Visit visit, TIntermAggregate *node) override; |
395 | |
396 | bool loopUnrollable; |
397 | |
398 | int loopIndexId; |
399 | }; |
400 | } |
401 | |
402 | #endif // COMPILER_OUTPUTASM_H_ |
403 | |