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
27namespace es2
28{
29 class Shader;
30}
31
32typedef unsigned int GLenum;
33
34namespace 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 &parameter, TIntermNode *argument, int index = 0);
279 void destination(sw::Shader::DestinationParameter &parameter, 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