Home | History | Annotate | Download | only in compiler
      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
    254 		virtual void visitSymbol(TIntermSymbol*);
    255 		virtual bool visitBinary(Visit visit, TIntermBinary*);
    256 		virtual bool visitUnary(Visit visit, TIntermUnary*);
    257 		virtual bool visitSelection(Visit visit, TIntermSelection*);
    258 		virtual bool visitAggregate(Visit visit, TIntermAggregate*);
    259 		virtual bool visitLoop(Visit visit, TIntermLoop*);
    260 		virtual bool visitBranch(Visit visit, TIntermBranch*);
    261 		virtual bool visitSwitch(Visit, TIntermSwitch*);
    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);
    273 		void argument(sw::Shader::SourceParameter &parameter, TIntermNode *argument, int index = 0);
    274 		void copy(TIntermTyped *dst, TIntermNode *src, int offset = 0);
    275 		void assignLvalue(TIntermTyped *dst, TIntermTyped *src);
    276 		int lvalue(sw::Shader::DestinationParameter &dst, Temporary &address, TIntermTyped *node);
    277 		sw::Shader::ParameterType registerType(TIntermTyped *operand);
    278 		bool hasFlatQualifier(TIntermTyped *operand);
    279 		unsigned int registerIndex(TIntermTyped *operand);
    280 		int writeMask(TIntermTyped *destination, int index = 0);
    281 		int readSwizzle(TIntermTyped *argument, int size);
    282 		bool trivial(TIntermTyped *expression, int budget);   // Fast to compute and no side effects
    283 		int cost(TIntermNode *expression, int budget);
    284 		const Function *findFunction(const TString &name);
    285 
    286 		int temporaryRegister(TIntermTyped *temporary);
    287 		int varyingRegister(TIntermTyped *varying);
    288 		void declareVarying(TIntermTyped *varying, int reg);
    289 		int uniformRegister(TIntermTyped *uniform);
    290 		int attributeRegister(TIntermTyped *attribute);
    291 		int fragmentOutputRegister(TIntermTyped *fragmentOutput);
    292 		int samplerRegister(TIntermTyped *sampler);
    293 		int samplerRegister(TIntermSymbol *sampler);
    294 		bool isSamplerRegister(TIntermTyped *operand);
    295 
    296 		typedef std::vector<TIntermTyped*> VariableArray;
    297 
    298 		int lookup(VariableArray &list, TIntermTyped *variable);
    299 		int lookup(VariableArray &list, TInterfaceBlock *block);
    300 		int blockMemberLookup(const TType &type, const TString &name, int registerIndex);
    301 		int allocate(VariableArray &list, TIntermTyped *variable);
    302 		void free(VariableArray &list, TIntermTyped *variable);
    303 
    304 		void declareUniform(const TType &type, const TString &name, int registerIndex, int blockId = -1, BlockLayoutEncoder* encoder = nullptr);
    305 		GLenum glVariableType(const TType &type);
    306 		GLenum glVariablePrecision(const TType &type);
    307 
    308 		static int dim(TIntermNode *v);
    309 		static int dim2(TIntermNode *m);
    310 		static unsigned int loopCount(TIntermLoop *node);
    311 
    312 		Shader *const shaderObject;
    313 		sw::Shader *shader;
    314 		sw::PixelShader *pixelShader;
    315 		sw::VertexShader *vertexShader;
    316 
    317 		VariableArray temporaries;
    318 		VariableArray uniforms;
    319 		VariableArray varyings;
    320 		VariableArray attributes;
    321 		VariableArray samplers;
    322 		VariableArray fragmentOutputs;
    323 
    324 		struct TypedMemberInfo : public BlockMemberInfo
    325 		{
    326 			TypedMemberInfo() {}
    327 			TypedMemberInfo(const BlockMemberInfo& b, const TType& t) : BlockMemberInfo(b), type(t) {}
    328 			TType type;
    329 		};
    330 		struct ArgumentInfo
    331 		{
    332 			ArgumentInfo(const BlockMemberInfo& b, const TType& t, int clampedIndex, int bufferIndex) :
    333 			    typedMemberInfo(b, t), clampedIndex(clampedIndex), bufferIndex(bufferIndex) {}
    334 			TypedMemberInfo typedMemberInfo;
    335 			int clampedIndex;
    336 			int bufferIndex;
    337 		};
    338 		int getBlockId(TIntermTyped *argument);
    339 		ArgumentInfo getArgumentInfo(TIntermTyped *argument, int index);
    340 
    341 		typedef std::map<int, TypedMemberInfo> BlockDefinitionIndexMap;
    342 		std::vector<BlockDefinitionIndexMap> blockDefinitions;
    343 
    344 		Scope emitScope;
    345 		Scope currentScope;
    346 
    347 		int currentFunction;
    348 		std::vector<Function> functionArray;
    349 
    350 		TQualifier outputQualifier;
    351 
    352 		TParseContext &mContext;
    353 	};
    354 
    355 	class LoopUnrollable : public TIntermTraverser
    356 	{
    357 	public:
    358 		bool traverse(TIntermNode *node);
    359 
    360 	private:
    361 		bool visitBranch(Visit visit, TIntermBranch *node);
    362 		bool visitLoop(Visit visit, TIntermLoop *loop);
    363 		bool visitAggregate(Visit visit, TIntermAggregate *node);
    364 
    365 		int loopDepth;
    366 		bool loopUnrollable;
    367 	};
    368 }
    369 
    370 #endif   // COMPILER_OUTPUTASM_H_
    371