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
22namespace sw
23{
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
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
72	VertexShader::~VertexShader()
73	{
74	}
75
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
147	bool VertexShader::containsTextureSampling() const
148	{
149		return textureSampling;
150	}
151
152	void VertexShader::analyze()
153	{
154		analyzeInput();
155		analyzeOutput();
156		analyzeDirtyConstants();
157		analyzeTextureSampling();
158		analyzeDynamicBranching();
159		analyzeSamplers();
160		analyzeCallSites();
161		analyzeDynamicIndexing();
162	}
163
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
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
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