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 #include "VertexShader.hpp"
16 
17 #include "Vertex.hpp"
18 #include "Debug.hpp"
19 
20 #include <string.h>
21 
22 namespace sw
23 {
VertexShader(const VertexShader * vs)24 	VertexShader::VertexShader(const VertexShader *vs) : Shader()
25 	{
26 		version = 0x0300;
27 		positionRegister = Pos;
28 		pointSizeRegister = Unused;
29 		instanceIdDeclared = false;
30 
31 		for(int i = 0; i < MAX_VERTEX_INPUTS; i++)
32 		{
33 			input[i] = Semantic(-1, -1);
34 		}
35 
36 		if(vs)   // Make a copy
37 		{
38 			for(size_t i = 0; i < vs->getLength(); i++)
39 			{
40 				append(new sw::Shader::Instruction(*vs->getInstruction(i)));
41 			}
42 
43 			memcpy(output, vs->output, sizeof(output));
44 			memcpy(input, vs->input, sizeof(input));
45 			positionRegister = vs->positionRegister;
46 			pointSizeRegister = vs->pointSizeRegister;
47 			instanceIdDeclared = vs->instanceIdDeclared;
48 			usedSamplers = vs->usedSamplers;
49 
50 			optimize();
51 			analyze();
52 		}
53 	}
54 
VertexShader(const unsigned long * token)55 	VertexShader::VertexShader(const unsigned long *token) : Shader()
56 	{
57 		parse(token);
58 
59 		positionRegister = Pos;
60 		pointSizeRegister = Unused;
61 		instanceIdDeclared = false;
62 
63 		for(int i = 0; i < MAX_VERTEX_INPUTS; i++)
64 		{
65 			input[i] = Semantic(-1, -1);
66 		}
67 
68 		optimize();
69 		analyze();
70 	}
71 
~VertexShader()72 	VertexShader::~VertexShader()
73 	{
74 	}
75 
validate(const unsigned long * const token)76 	int VertexShader::validate(const unsigned long *const token)
77 	{
78 		if(!token)
79 		{
80 			return 0;
81 		}
82 
83 		unsigned short version = (unsigned short)(token[0] & 0x0000FFFF);
84 		unsigned char majorVersion = (unsigned char)((token[0] & 0x0000FF00) >> 8);
85 		ShaderType shaderType = (ShaderType)((token[0] & 0xFFFF0000) >> 16);
86 
87 		if(shaderType != SHADER_VERTEX || majorVersion > 3)
88 		{
89 			return 0;
90 		}
91 
92 		int instructionCount = 1;
93 
94 		for(int i = 0; token[i] != 0x0000FFFF; i++)
95 		{
96 			if((token[i] & 0x0000FFFF) == 0x0000FFFE)   // Comment token
97 			{
98 				int length = (token[i] & 0x7FFF0000) >> 16;
99 
100 				i += length;
101 			}
102 			else
103 			{
104 				Shader::Opcode opcode = (Shader::Opcode)(token[i] & 0x0000FFFF);
105 
106 				switch(opcode)
107 				{
108 				case Shader::OPCODE_TEXCOORD:
109 				case Shader::OPCODE_TEXKILL:
110 				case Shader::OPCODE_TEX:
111 				case Shader::OPCODE_TEXBEM:
112 				case Shader::OPCODE_TEXBEML:
113 				case Shader::OPCODE_TEXREG2AR:
114 				case Shader::OPCODE_TEXREG2GB:
115 				case Shader::OPCODE_TEXM3X2PAD:
116 				case Shader::OPCODE_TEXM3X2TEX:
117 				case Shader::OPCODE_TEXM3X3PAD:
118 				case Shader::OPCODE_TEXM3X3TEX:
119 				case Shader::OPCODE_RESERVED0:
120 				case Shader::OPCODE_TEXM3X3SPEC:
121 				case Shader::OPCODE_TEXM3X3VSPEC:
122 				case Shader::OPCODE_TEXREG2RGB:
123 				case Shader::OPCODE_TEXDP3TEX:
124 				case Shader::OPCODE_TEXM3X2DEPTH:
125 				case Shader::OPCODE_TEXDP3:
126 				case Shader::OPCODE_TEXM3X3:
127 				case Shader::OPCODE_TEXDEPTH:
128 				case Shader::OPCODE_CMP0:
129 				case Shader::OPCODE_BEM:
130 				case Shader::OPCODE_DP2ADD:
131 				case Shader::OPCODE_DFDX:
132 				case Shader::OPCODE_DFDY:
133 				case Shader::OPCODE_TEXLDD:
134 					return 0;   // Unsupported operation
135 				default:
136 					instructionCount++;
137 					break;
138 				}
139 
140 				i += size(token[i], version);
141 			}
142 		}
143 
144 		return instructionCount;
145 	}
146 
containsTextureSampling() const147 	bool VertexShader::containsTextureSampling() const
148 	{
149 		return textureSampling;
150 	}
151 
analyze()152 	void VertexShader::analyze()
153 	{
154 		analyzeInput();
155 		analyzeOutput();
156 		analyzeDirtyConstants();
157 		analyzeTextureSampling();
158 		analyzeDynamicBranching();
159 		analyzeSamplers();
160 		analyzeCallSites();
161 		analyzeDynamicIndexing();
162 	}
163 
analyzeInput()164 	void VertexShader::analyzeInput()
165 	{
166 		for(unsigned int i = 0; i < instruction.size(); i++)
167 		{
168 			if(instruction[i]->opcode == Shader::OPCODE_DCL &&
169 			   instruction[i]->dst.type == Shader::PARAMETER_INPUT)
170 			{
171 				int index = instruction[i]->dst.index;
172 
173 				input[index] = Semantic(instruction[i]->usage, instruction[i]->usageIndex);
174 			}
175 		}
176 	}
177 
analyzeOutput()178 	void VertexShader::analyzeOutput()
179 	{
180 		if(version < 0x0300)
181 		{
182 			output[Pos][0] = Semantic(Shader::USAGE_POSITION, 0);
183 			output[Pos][1] = Semantic(Shader::USAGE_POSITION, 0);
184 			output[Pos][2] = Semantic(Shader::USAGE_POSITION, 0);
185 			output[Pos][3] = Semantic(Shader::USAGE_POSITION, 0);
186 
187 			for(unsigned int i = 0; i < instruction.size(); i++)
188 			{
189 				const DestinationParameter &dst = instruction[i]->dst;
190 
191 				switch(dst.type)
192 				{
193 				case Shader::PARAMETER_RASTOUT:
194 					switch(dst.index)
195 					{
196 					case 0:
197 						// Position already assumed written
198 						break;
199 					case 1:
200 						output[Fog][0] = Semantic(Shader::USAGE_FOG, 0);
201 						break;
202 					case 2:
203 						output[Pts][1] = Semantic(Shader::USAGE_PSIZE, 0);
204 						pointSizeRegister = Pts;
205 						break;
206 					default: ASSERT(false);
207 					}
208 					break;
209 				case Shader::PARAMETER_ATTROUT:
210 					if(dst.index == 0)
211 					{
212 						if(dst.x) output[C0][0] = Semantic(Shader::USAGE_COLOR, 0);
213 						if(dst.y) output[C0][1] = Semantic(Shader::USAGE_COLOR, 0);
214 						if(dst.z) output[C0][2] = Semantic(Shader::USAGE_COLOR, 0);
215 						if(dst.w) output[C0][3] = Semantic(Shader::USAGE_COLOR, 0);
216 					}
217 					else if(dst.index == 1)
218 					{
219 						if(dst.x) output[C1][0] = Semantic(Shader::USAGE_COLOR, 1);
220 						if(dst.y) output[C1][1] = Semantic(Shader::USAGE_COLOR, 1);
221 						if(dst.z) output[C1][2] = Semantic(Shader::USAGE_COLOR, 1);
222 						if(dst.w) output[C1][3] = Semantic(Shader::USAGE_COLOR, 1);
223 					}
224 					else ASSERT(false);
225 					break;
226 				case Shader::PARAMETER_TEXCRDOUT:
227 					if(dst.x) output[T0 + dst.index][0] = Semantic(Shader::USAGE_TEXCOORD, dst.index);
228 					if(dst.y) output[T0 + dst.index][1] = Semantic(Shader::USAGE_TEXCOORD, dst.index);
229 					if(dst.z) output[T0 + dst.index][2] = Semantic(Shader::USAGE_TEXCOORD, dst.index);
230 					if(dst.w) output[T0 + dst.index][3] = Semantic(Shader::USAGE_TEXCOORD, dst.index);
231 					break;
232 				default:
233 					break;
234 				}
235 			}
236 		}
237 		else   // Shader Model 3.0 input declaration
238 		{
239 			for(unsigned int i = 0; i < instruction.size(); i++)
240 			{
241 				if(instruction[i]->opcode == Shader::OPCODE_DCL &&
242 				   instruction[i]->dst.type == Shader::PARAMETER_OUTPUT)
243 				{
244 					unsigned char usage = instruction[i]->usage;
245 					unsigned char usageIndex = instruction[i]->usageIndex;
246 
247 					const DestinationParameter &dst = instruction[i]->dst;
248 
249 					if(dst.x) output[dst.index][0] = Semantic(usage, usageIndex);
250 					if(dst.y) output[dst.index][1] = Semantic(usage, usageIndex);
251 					if(dst.z) output[dst.index][2] = Semantic(usage, usageIndex);
252 					if(dst.w) output[dst.index][3] = Semantic(usage, usageIndex);
253 
254 					if(usage == Shader::USAGE_POSITION && usageIndex == 0)
255 					{
256 						positionRegister = dst.index;
257 					}
258 
259 					if(usage == Shader::USAGE_PSIZE && usageIndex == 0)
260 					{
261 						pointSizeRegister = dst.index;
262 					}
263 				}
264 			}
265 		}
266 	}
267 
analyzeTextureSampling()268 	void VertexShader::analyzeTextureSampling()
269 	{
270 		textureSampling = false;
271 
272 		for(unsigned int i = 0; i < instruction.size() && !textureSampling; i++)
273 		{
274 			if(instruction[i]->src[1].type == PARAMETER_SAMPLER)
275 			{
276 				textureSampling = true;
277 			}
278 		}
279 	}
280 }
281