blob: 641ec501df0edbe5995f057786a9a926eacc308b [file] [log] [blame]
Nicolas Capens0bac2852016-05-07 06:09:58 -04001// 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
Alexis Hetu924513c2018-01-05 15:48:12 -050058 struct ShaderVariable
Nicolas Capens0bac2852016-05-07 06:09:58 -040059 {
Alexis Hetu924513c2018-01-05 15:48:12 -050060 ShaderVariable(const TType& type, const std::string& name, int registerIndex);
Nicolas Capens0bac2852016-05-07 06:09:58 -040061
62 GLenum type;
63 GLenum precision;
64 std::string name;
65 int arraySize;
66
67 int registerIndex;
68
Alexis Hetu924513c2018-01-05 15:48:12 -050069 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
Nicolas Capens0bac2852016-05-07 06:09:58 -040076 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(bool rowMajor);
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 bool isRowMajor;
121
122 void nextRegister();
123
124 virtual void getBlockLayoutInfo(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) = 0;
125 virtual void advanceOffset(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) = 0;
126 };
127
128 // Block layout according to the std140 block layout
129 // See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification
130 class Std140BlockEncoder : public BlockLayoutEncoder
131 {
132 public:
133 Std140BlockEncoder(bool rowMajor);
134
135 void enterAggregateType() override;
136 void exitAggregateType() override;
137
138 protected:
139 void getBlockLayoutInfo(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) override;
140 void advanceOffset(const TType &type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) override;
141 };
142
143 typedef std::vector<UniformBlock> ActiveUniformBlocks;
144
145 struct Attribute
146 {
147 Attribute();
148 Attribute(GLenum type, const std::string &name, int arraySize, int location, int registerIndex);
149
150 GLenum type;
151 std::string name;
152 int arraySize;
153 int location;
154
155 int registerIndex;
156 };
157
158 typedef std::vector<Attribute> ActiveAttributes;
159
Alexis Hetu924513c2018-01-05 15:48:12 -0500160 struct Varying : public ShaderVariable
Nicolas Capens0bac2852016-05-07 06:09:58 -0400161 {
Alexis Hetu924513c2018-01-05 15:48:12 -0500162 Varying(const TType& type, const std::string &name, int reg = -1, int col = -1)
163 : ShaderVariable(type, name, reg), qualifier(type.getQualifier()), col(col)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400164 {
165 }
166
167 bool isArray() const
168 {
169 return arraySize >= 1;
170 }
171
172 int size() const // Unify with es2::Uniform?
173 {
174 return arraySize > 0 ? arraySize : 1;
175 }
176
Alexis Hetu743913c2018-01-04 11:54:55 -0500177 TQualifier qualifier;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400178 int col; // First register element, assigned during link
179 };
180
181 typedef std::list<Varying> VaryingList;
182
183 class Shader
184 {
185 friend class OutputASM;
186 public:
187 virtual ~Shader() {};
188 virtual sw::Shader *getShader() const = 0;
189 virtual sw::PixelShader *getPixelShader() const;
190 virtual sw::VertexShader *getVertexShader() const;
Alexis Hetu23f54d72017-12-05 16:03:51 -0500191 int getShaderVersion() const { return shaderVersion; }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400192
193 protected:
194 VaryingList varyings;
195 ActiveUniforms activeUniforms;
Alexis Hetu924513c2018-01-05 15:48:12 -0500196 ActiveUniforms activeUniformStructs;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400197 ActiveAttributes activeAttributes;
198 ActiveUniformBlocks activeUniformBlocks;
Alexis Hetu23f54d72017-12-05 16:03:51 -0500199 int shaderVersion;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400200 };
201
202 struct Function
203 {
204 Function(int label, const char *name, TIntermSequence *arg, TIntermTyped *ret) : label(label), name(name), arg(arg), ret(ret)
205 {
206 }
207
208 Function(int label, const TString &name, TIntermSequence *arg, TIntermTyped *ret) : label(label), name(name), arg(arg), ret(ret)
209 {
210 }
211
212 int label;
213 TString name;
214 TIntermSequence *arg;
215 TIntermTyped *ret;
216 };
217
218 typedef sw::Shader::Instruction Instruction;
219
220 class Temporary;
221
222 class OutputASM : public TIntermTraverser
223 {
224 public:
225 explicit OutputASM(TParseContext &context, Shader *shaderObject);
226 ~OutputASM();
227
228 void output();
229
230 void freeTemporary(Temporary *temporary);
231
232 private:
233 enum Scope
234 {
235 GLOBAL,
236 FUNCTION
237 };
238
239 struct TextureFunction
240 {
241 TextureFunction(const TString& name);
242
243 enum Method
244 {
245 IMPLICIT, // Mipmap LOD determined implicitly (standard lookup)
246 LOD,
247 SIZE, // textureSize()
248 FETCH,
249 GRAD
250 };
251
252 Method method;
253 bool proj;
254 bool offset;
255 };
256
257 void emitShader(Scope scope);
258
259 // Visit AST nodes and output their code to the body stream
Nicolas Capens0530b452017-11-15 16:39:47 -0500260 void visitSymbol(TIntermSymbol*) override;
261 bool visitBinary(Visit visit, TIntermBinary*) override;
262 bool visitUnary(Visit visit, TIntermUnary*) override;
263 bool visitSelection(Visit visit, TIntermSelection*) override;
264 bool visitAggregate(Visit visit, TIntermAggregate*) override;
265 bool visitLoop(Visit visit, TIntermLoop*) override;
266 bool visitBranch(Visit visit, TIntermBranch*) override;
267 bool visitSwitch(Visit, TIntermSwitch*) override;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400268
269 sw::Shader::Opcode getOpcode(sw::Shader::Opcode op, TIntermTyped *in) const;
270 Instruction *emit(sw::Shader::Opcode op, TIntermTyped *dst = 0, TIntermNode *src0 = 0, TIntermNode *src1 = 0, TIntermNode *src2 = 0, TIntermNode *src3 = 0, TIntermNode *src4 = 0);
271 Instruction *emit(sw::Shader::Opcode op, TIntermTyped *dst, int dstIndex, TIntermNode *src0 = 0, int index0 = 0, TIntermNode *src1 = 0, int index1 = 0,
272 TIntermNode *src2 = 0, int index2 = 0, TIntermNode *src3 = 0, int index3 = 0, TIntermNode *src4 = 0, int index4 = 0);
273 Instruction *emitCast(TIntermTyped *dst, TIntermTyped *src);
274 Instruction *emitCast(TIntermTyped *dst, int dstIndex, TIntermTyped *src, int srcIndex);
275 void emitBinary(sw::Shader::Opcode op, TIntermTyped *dst = 0, TIntermNode *src0 = 0, TIntermNode *src1 = 0, TIntermNode *src2 = 0);
276 void emitAssign(sw::Shader::Opcode op, TIntermTyped *result, TIntermTyped *lhs, TIntermTyped *src0, TIntermTyped *src1 = 0);
277 void emitCmp(sw::Shader::Control cmpOp, TIntermTyped *dst, TIntermNode *left, TIntermNode *right, int index = 0);
278 void emitDeterminant(TIntermTyped *result, TIntermTyped *arg, int size, int col = -1, int row = -1, int outCol = 0, int outRow = 0);
Nicolas Capens0530b452017-11-15 16:39:47 -0500279 void source(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index = 0);
280 void destination(sw::Shader::DestinationParameter &parameter, TIntermTyped *argument, int index = 0);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400281 void copy(TIntermTyped *dst, TIntermNode *src, int offset = 0);
282 void assignLvalue(TIntermTyped *dst, TIntermTyped *src);
Nicolas Capensd469de22017-11-16 10:42:20 -0500283 void evaluateRvalue(TIntermTyped *node);
Nicolas Capens6986b282017-11-16 10:38:19 -0500284 int lvalue(sw::Shader::DestinationParameter &dst, TIntermTyped *node);
Nicolas Capens0530b452017-11-15 16:39:47 -0500285 int lvalue(TIntermTyped *&root, unsigned int &offset, sw::Shader::Relative &rel, unsigned char &mask, Temporary &address, TIntermTyped *node);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400286 sw::Shader::ParameterType registerType(TIntermTyped *operand);
Alexis Hetu12b00502016-05-20 13:01:11 -0400287 bool hasFlatQualifier(TIntermTyped *operand);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400288 unsigned int registerIndex(TIntermTyped *operand);
289 int writeMask(TIntermTyped *destination, int index = 0);
290 int readSwizzle(TIntermTyped *argument, int size);
291 bool trivial(TIntermTyped *expression, int budget); // Fast to compute and no side effects
292 int cost(TIntermNode *expression, int budget);
293 const Function *findFunction(const TString &name);
294
295 int temporaryRegister(TIntermTyped *temporary);
296 int varyingRegister(TIntermTyped *varying);
Alexis Hetu49351232017-11-02 16:00:32 -0400297 void setPixelShaderInputs(const TType& type, int var, bool flat);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400298 void declareVarying(TIntermTyped *varying, int reg);
Alexis Hetu49351232017-11-02 16:00:32 -0400299 void declareVarying(const TType &type, const TString &name, int registerIndex);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400300 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
307 typedef std::vector<TIntermTyped*> VariableArray;
308
309 int lookup(VariableArray &list, TIntermTyped *variable);
310 int lookup(VariableArray &list, TInterfaceBlock *block);
311 int blockMemberLookup(const TType &type, const TString &name, int registerIndex);
Alexis Hetuda163ed2018-01-03 16:36:14 -0500312 int allocate(VariableArray &list, TIntermTyped *variable, bool samplersOnly = false);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400313 void free(VariableArray &list, TIntermTyped *variable);
314
Alexis Hetuda163ed2018-01-03 16:36:14 -0500315 void declareUniform(const TType &type, const TString &name, int registerIndex, bool samplersOnly, int blockId = -1, BlockLayoutEncoder* encoder = nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400316
317 static int dim(TIntermNode *v);
318 static int dim2(TIntermNode *m);
319 static unsigned int loopCount(TIntermLoop *node);
320
321 Shader *const shaderObject;
322 sw::Shader *shader;
323 sw::PixelShader *pixelShader;
324 sw::VertexShader *vertexShader;
325
326 VariableArray temporaries;
327 VariableArray uniforms;
328 VariableArray varyings;
329 VariableArray attributes;
330 VariableArray samplers;
331 VariableArray fragmentOutputs;
332
333 struct TypedMemberInfo : public BlockMemberInfo
334 {
335 TypedMemberInfo() {}
336 TypedMemberInfo(const BlockMemberInfo& b, const TType& t) : BlockMemberInfo(b), type(t) {}
337 TType type;
338 };
339 struct ArgumentInfo
340 {
341 ArgumentInfo(const BlockMemberInfo& b, const TType& t, int clampedIndex, int bufferIndex) :
342 typedMemberInfo(b, t), clampedIndex(clampedIndex), bufferIndex(bufferIndex) {}
343 TypedMemberInfo typedMemberInfo;
344 int clampedIndex;
345 int bufferIndex;
346 };
347 int getBlockId(TIntermTyped *argument);
348 ArgumentInfo getArgumentInfo(TIntermTyped *argument, int index);
349
350 typedef std::map<int, TypedMemberInfo> BlockDefinitionIndexMap;
351 std::vector<BlockDefinitionIndexMap> blockDefinitions;
352
353 Scope emitScope;
354 Scope currentScope;
355
356 int currentFunction;
357 std::vector<Function> functionArray;
358
359 TQualifier outputQualifier;
360
361 TParseContext &mContext;
362 };
363
364 class LoopUnrollable : public TIntermTraverser
365 {
366 public:
367 bool traverse(TIntermNode *node);
368
369 private:
370 bool visitBranch(Visit visit, TIntermBranch *node);
371 bool visitLoop(Visit visit, TIntermLoop *loop);
372 bool visitAggregate(Visit visit, TIntermAggregate *node);
373
374 int loopDepth;
375 bool loopUnrollable;
376 };
377}
378
379#endif // COMPILER_OUTPUTASM_H_