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