• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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 <spirv/unified1/spirv.hpp>
16 #include "SpirvShader.hpp"
17 #include "System/Math.hpp"
18 #include "Vulkan/VkDebug.hpp"
19 #include "Device/Config.hpp"
20 
21 namespace sw
22 {
23 	volatile int SpirvShader::serialCounter = 1;    // Start at 1, 0 is invalid shader.
24 
SpirvShader(InsnStore const & insns)25 	SpirvShader::SpirvShader(InsnStore const &insns)
26 			: insns{insns}, inputs{MAX_INTERFACE_COMPONENTS},
27 			  outputs{MAX_INTERFACE_COMPONENTS},
28 			  serialID{serialCounter++}, modes{}
29 	{
30 		// Simplifying assumptions (to be satisfied by earlier transformations)
31 		// - There is exactly one entrypoint in the module, and it's the one we want
32 		// - The only input/output OpVariables present are those used by the entrypoint
33 
34 		for (auto insn : *this)
35 		{
36 			switch (insn.opcode())
37 			{
38 			case spv::OpExecutionMode:
39 				ProcessExecutionMode(insn);
40 				break;
41 
42 			case spv::OpDecorate:
43 			{
44 				auto targetId = insn.word(1);
45 				decorations[targetId].Apply(
46 						static_cast<spv::Decoration>(insn.word(2)),
47 						insn.wordCount() > 3 ? insn.word(3) : 0);
48 				break;
49 			}
50 
51 			case spv::OpMemberDecorate:
52 			{
53 				auto targetId = insn.word(1);
54 				auto memberIndex = insn.word(2);
55 				auto &d = memberDecorations[targetId];
56 				if (memberIndex >= d.size())
57 					d.resize(memberIndex + 1);    // on demand; exact size would require another pass...
58 				d[memberIndex].Apply(
59 						static_cast<spv::Decoration>(insn.word(3)),
60 						insn.wordCount() > 4 ? insn.word(4) : 0);
61 				break;
62 			}
63 
64 			case spv::OpDecorationGroup:
65 				// Nothing to do here. We don't need to record the definition of the group; we'll just have
66 				// the bundle of decorations float around. If we were to ever walk the decorations directly,
67 				// we might think about introducing this as a real Object.
68 				break;
69 
70 			case spv::OpGroupDecorate:
71 			{
72 				auto const &srcDecorations = decorations[insn.word(1)];
73 				for (auto i = 2u; i < insn.wordCount(); i++)
74 				{
75 					// remaining operands are targets to apply the group to.
76 					decorations[insn.word(i)].Apply(srcDecorations);
77 				}
78 				break;
79 			}
80 
81 			case spv::OpGroupMemberDecorate:
82 			{
83 				auto const &srcDecorations = decorations[insn.word(1)];
84 				for (auto i = 2u; i < insn.wordCount(); i += 2)
85 				{
86 					// remaining operands are pairs of <id>, literal for members to apply to.
87 					auto &d = memberDecorations[insn.word(i)];
88 					auto memberIndex = insn.word(i + 1);
89 					if (memberIndex >= d.size())
90 						d.resize(memberIndex + 1);    // on demand resize, see above...
91 					d[memberIndex].Apply(srcDecorations);
92 				}
93 				break;
94 			}
95 
96 			case spv::OpTypeVoid:
97 			case spv::OpTypeBool:
98 			case spv::OpTypeInt:
99 			case spv::OpTypeFloat:
100 			case spv::OpTypeVector:
101 			case spv::OpTypeMatrix:
102 			case spv::OpTypeImage:
103 			case spv::OpTypeSampler:
104 			case spv::OpTypeSampledImage:
105 			case spv::OpTypeArray:
106 			case spv::OpTypeRuntimeArray:
107 			case spv::OpTypeStruct:
108 			case spv::OpTypePointer:
109 			case spv::OpTypeFunction:
110 			{
111 				auto resultId = insn.word(1);
112 				auto &object = types[resultId];
113 				object.kind = Object::Kind::Type;
114 				object.definition = insn;
115 				object.sizeInComponents = ComputeTypeSize(insn);
116 
117 				// A structure is a builtin block if it has a builtin
118 				// member. All members of such a structure are builtins.
119 				if (insn.opcode() == spv::OpTypeStruct)
120 				{
121 					auto d = memberDecorations.find(resultId);
122 					if (d != memberDecorations.end())
123 					{
124 						for (auto &m : d->second)
125 						{
126 							if (m.HasBuiltIn)
127 							{
128 								object.isBuiltInBlock = true;
129 								break;
130 							}
131 						}
132 					}
133 				}
134 				else if (insn.opcode() == spv::OpTypePointer)
135 				{
136 					auto pointeeType = insn.word(3);
137 					object.isBuiltInBlock = getType(pointeeType).isBuiltInBlock;
138 				}
139 				break;
140 			}
141 
142 			case spv::OpVariable:
143 			{
144 				auto typeId = insn.word(1);
145 				auto resultId = insn.word(2);
146 				auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
147 				if (insn.wordCount() > 4)
148 					UNIMPLEMENTED("Variable initializers not yet supported");
149 
150 				auto &object = defs[resultId];
151 				object.kind = Object::Kind::Variable;
152 				object.definition = insn;
153 				object.storageClass = storageClass;
154 
155 				auto &type = getType(typeId);
156 
157 				object.sizeInComponents = type.sizeInComponents;
158 				object.isBuiltInBlock = type.isBuiltInBlock;
159 
160 				// Register builtins
161 
162 				if (storageClass == spv::StorageClassInput || storageClass == spv::StorageClassOutput)
163 				{
164 					ProcessInterfaceVariable(object);
165 				}
166 				break;
167 			}
168 
169 			case spv::OpConstant:
170 			case spv::OpConstantComposite:
171 			case spv::OpConstantFalse:
172 			case spv::OpConstantTrue:
173 			case spv::OpConstantNull:
174 			{
175 				auto typeId = insn.word(1);
176 				auto resultId = insn.word(2);
177 				auto &object = defs[resultId];
178 				object.kind = Object::Kind::Constant;
179 				object.definition = insn;
180 				object.sizeInComponents = getType(typeId).sizeInComponents;
181 				break;
182 			}
183 
184 			case spv::OpCapability:
185 				// Various capabilities will be declared, but none affect our code generation at this point.
186 			case spv::OpMemoryModel:
187 				// Memory model does not affect our code generation until we decide to do Vulkan Memory Model support.
188 			case spv::OpEntryPoint:
189 				// Due to preprocessing, the entrypoint provides no value.
190 				break;
191 
192 			default:
193 				break;    // This is OK, these passes are intentionally partial
194 			}
195 		}
196 	}
197 
ProcessInterfaceVariable(Object & object)198 	void SpirvShader::ProcessInterfaceVariable(Object &object)
199 	{
200 		assert(object.storageClass == spv::StorageClassInput || object.storageClass == spv::StorageClassOutput);
201 
202 		auto &builtinInterface = (object.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
203 		auto &userDefinedInterface = (object.storageClass == spv::StorageClassInput) ? inputs : outputs;
204 
205 		auto resultId = object.definition.word(2);
206 		if (object.isBuiltInBlock)
207 		{
208 			// walk the builtin block, registering each of its members separately.
209 			auto ptrType = getType(object.definition.word(1)).definition;
210 			assert(ptrType.opcode() == spv::OpTypePointer);
211 			auto pointeeType = ptrType.word(3);
212 			auto m = memberDecorations.find(pointeeType);
213 			assert(m != memberDecorations.end());        // otherwise we wouldn't have marked the type chain
214 			auto &structType = getType(pointeeType).definition;
215 			auto offset = 0u;
216 			auto word = 2u;
217 			for (auto &member : m->second)
218 			{
219 				auto &memberType = getType(structType.word(word));
220 
221 				if (member.HasBuiltIn)
222 				{
223 					builtinInterface[member.BuiltIn] = {resultId, offset, memberType.sizeInComponents};
224 				}
225 
226 				offset += memberType.sizeInComponents;
227 				++word;
228 			}
229 			return;
230 		}
231 
232 		auto d = decorations.find(resultId);
233 		if (d != decorations.end() && d->second.HasBuiltIn)
234 		{
235 			builtinInterface[d->second.BuiltIn] = {resultId, 0, object.sizeInComponents};
236 		}
237 		else
238 		{
239 			object.kind = Object::Kind::InterfaceVariable;
240 			PopulateInterface(&userDefinedInterface, resultId);
241 		}
242 	}
243 
ProcessExecutionMode(InsnIterator insn)244 	void SpirvShader::ProcessExecutionMode(InsnIterator insn)
245 	{
246 		auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
247 		switch (mode)
248 		{
249 		case spv::ExecutionModeEarlyFragmentTests:
250 			modes.EarlyFragmentTests = true;
251 			break;
252 		case spv::ExecutionModeDepthReplacing:
253 			modes.DepthReplacing = true;
254 			break;
255 		case spv::ExecutionModeDepthGreater:
256 			modes.DepthGreater = true;
257 			break;
258 		case spv::ExecutionModeDepthLess:
259 			modes.DepthLess = true;
260 			break;
261 		case spv::ExecutionModeDepthUnchanged:
262 			modes.DepthUnchanged = true;
263 			break;
264 		case spv::ExecutionModeLocalSize:
265 			modes.LocalSizeX = insn.word(3);
266 			modes.LocalSizeZ = insn.word(5);
267 			modes.LocalSizeY = insn.word(4);
268 			break;
269 		case spv::ExecutionModeOriginUpperLeft:
270 			// This is always the case for a Vulkan shader. Do nothing.
271 			break;
272 		default:
273 			UNIMPLEMENTED("No other execution modes are permitted");
274 		}
275 	}
276 
ComputeTypeSize(sw::SpirvShader::InsnIterator insn)277 	uint32_t SpirvShader::ComputeTypeSize(sw::SpirvShader::InsnIterator insn)
278 	{
279 		// Types are always built from the bottom up (with the exception of forward ptrs, which
280 		// don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
281 		// already been described (and so their sizes determined)
282 		switch (insn.opcode())
283 		{
284 		case spv::OpTypeVoid:
285 		case spv::OpTypeSampler:
286 		case spv::OpTypeImage:
287 		case spv::OpTypeSampledImage:
288 		case spv::OpTypeFunction:
289 		case spv::OpTypeRuntimeArray:
290 			// Objects that don't consume any space.
291 			// Descriptor-backed objects currently only need exist at compile-time.
292 			// Runtime arrays don't appear in places where their size would be interesting
293 			return 0;
294 
295 		case spv::OpTypeBool:
296 		case spv::OpTypeFloat:
297 		case spv::OpTypeInt:
298 			// All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
299 			// we might need to change this, but only 32 bit components are required for Vulkan 1.1.
300 			return 1;
301 
302 		case spv::OpTypeVector:
303 		case spv::OpTypeMatrix:
304 			// Vectors and matrices both consume element count * element size.
305 			return getType(insn.word(2)).sizeInComponents * insn.word(3);
306 
307 		case spv::OpTypeArray:
308 		{
309 			// Element count * element size. Array sizes come from constant ids.
310 			auto arraySize = GetConstantInt(insn.word(3));
311 			return getType(insn.word(2)).sizeInComponents * arraySize;
312 		}
313 
314 		case spv::OpTypeStruct:
315 		{
316 			uint32_t size = 0;
317 			for (uint32_t i = 2u; i < insn.wordCount(); i++)
318 			{
319 				size += getType(insn.word(i)).sizeInComponents;
320 			}
321 			return size;
322 		}
323 
324 		case spv::OpTypePointer:
325 			// Pointer 'size' is just pointee size
326 			// TODO: this isn't really correct. we should look through pointers as appropriate.
327 			return getType(insn.word(3)).sizeInComponents;
328 
329 		default:
330 			// Some other random insn.
331 			UNIMPLEMENTED("Only types are supported");
332 		}
333 	}
334 
PopulateInterfaceSlot(std::vector<InterfaceComponent> * iface,Decorations const & d,AttribType type)335 	void SpirvShader::PopulateInterfaceSlot(std::vector<InterfaceComponent> *iface, Decorations const &d, AttribType type)
336 	{
337 		// Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
338 		auto scalarSlot = (d.Location << 2) | d.Component;
339 
340 		auto &slot = (*iface)[scalarSlot];
341 		slot.Type = type;
342 		slot.Flat = d.Flat;
343 		slot.NoPerspective = d.NoPerspective;
344 		slot.Centroid = d.Centroid;
345 	}
346 
PopulateInterfaceInner(std::vector<InterfaceComponent> * iface,uint32_t id,Decorations d)347 	int SpirvShader::PopulateInterfaceInner(std::vector<InterfaceComponent> *iface, uint32_t id, Decorations d)
348 	{
349 		// Recursively walks variable definition and its type tree, taking into account
350 		// any explicit Location or Component decorations encountered; where explicit
351 		// Locations or Components are not specified, assigns them sequentially.
352 		// Collected decorations are carried down toward the leaves and across
353 		// siblings; Effect of decorations intentionally does not flow back up the tree.
354 		//
355 		// Returns the next available location.
356 
357 		// This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
358 
359 		auto const it = decorations.find(id);
360 		if (it != decorations.end())
361 		{
362 			d.Apply(it->second);
363 		}
364 
365 		auto const &obj = getType(id);
366 		switch (obj.definition.opcode())
367 		{
368 		case spv::OpTypePointer:
369 			return PopulateInterfaceInner(iface, obj.definition.word(3), d);
370 		case spv::OpTypeMatrix:
371 			for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
372 			{
373 				// consumes same components of N consecutive locations
374 				PopulateInterfaceInner(iface, obj.definition.word(2), d);
375 			}
376 			return d.Location;
377 		case spv::OpTypeVector:
378 			for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
379 			{
380 				// consumes N consecutive components in the same location
381 				PopulateInterfaceInner(iface, obj.definition.word(2), d);
382 			}
383 			return d.Location + 1;
384 		case spv::OpTypeFloat:
385 			PopulateInterfaceSlot(iface, d, ATTRIBTYPE_FLOAT);
386 			return d.Location + 1;
387 		case spv::OpTypeInt:
388 			PopulateInterfaceSlot(iface, d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
389 			return d.Location + 1;
390 		case spv::OpTypeBool:
391 			PopulateInterfaceSlot(iface, d, ATTRIBTYPE_UINT);
392 			return d.Location + 1;
393 		case spv::OpTypeStruct:
394 		{
395 			auto const memberDecorationsIt = memberDecorations.find(id);
396 			// iterate over members, which may themselves have Location/Component decorations
397 			for (auto i = 0u; i < obj.definition.wordCount() - 2; i++)
398 			{
399 				// Apply any member decorations for this member to the carried state.
400 				if (memberDecorationsIt != memberDecorations.end() && i < memberDecorationsIt->second.size())
401 				{
402 					d.Apply(memberDecorationsIt->second[i]);
403 				}
404 				d.Location = PopulateInterfaceInner(iface, obj.definition.word(i + 2), d);
405 				d.Component = 0;    // Implicit locations always have component=0
406 			}
407 			return d.Location;
408 		}
409 		case spv::OpTypeArray:
410 		{
411 			auto arraySize = GetConstantInt(obj.definition.word(3));
412 			for (auto i = 0u; i < arraySize; i++)
413 			{
414 				d.Location = PopulateInterfaceInner(iface, obj.definition.word(2), d);
415 			}
416 			return d.Location;
417 		}
418 		default:
419 			// Intentionally partial; most opcodes do not participate in type hierarchies
420 			return 0;
421 		}
422 	}
423 
PopulateInterface(std::vector<InterfaceComponent> * iface,uint32_t id)424 	void SpirvShader::PopulateInterface(std::vector<InterfaceComponent> *iface, uint32_t id)
425 	{
426 		// Walk a variable definition and populate the interface from it.
427 		Decorations d{};
428 
429 		auto const it = decorations.find(id);
430 		if (it != decorations.end())
431 		{
432 			d.Apply(it->second);
433 		}
434 
435 		auto def = getObject(id).definition;
436 		assert(def.opcode() == spv::OpVariable);
437 		PopulateInterfaceInner(iface, def.word(1), d);
438 	}
439 
Apply(spv::Decoration decoration,uint32_t arg)440 	void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
441 	{
442 		switch (decoration)
443 		{
444 		case spv::DecorationLocation:
445 			HasLocation = true;
446 			Location = static_cast<int32_t>(arg);
447 			break;
448 		case spv::DecorationComponent:
449 			HasComponent = true;
450 			Component = arg;
451 			break;
452 		case spv::DecorationBuiltIn:
453 			HasBuiltIn = true;
454 			BuiltIn = static_cast<spv::BuiltIn>(arg);
455 			break;
456 		case spv::DecorationFlat:
457 			Flat = true;
458 			break;
459 		case spv::DecorationNoPerspective:
460 			NoPerspective = true;
461 			break;
462 		case spv::DecorationCentroid:
463 			Centroid = true;
464 			break;
465 		case spv::DecorationBlock:
466 			Block = true;
467 			break;
468 		case spv::DecorationBufferBlock:
469 			BufferBlock = true;
470 			break;
471 		default:
472 			// Intentionally partial, there are many decorations we just don't care about.
473 			break;
474 		}
475 	}
476 
Apply(const sw::SpirvShader::Decorations & src)477 	void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
478 	{
479 		// Apply a decoration group to this set of decorations
480 		if (src.HasBuiltIn)
481 		{
482 			HasBuiltIn = true;
483 			BuiltIn = src.BuiltIn;
484 		}
485 
486 		if (src.HasLocation)
487 		{
488 			HasLocation = true;
489 			Location = src.Location;
490 		}
491 
492 		if (src.HasComponent)
493 		{
494 			HasComponent = true;
495 			Component = src.Component;
496 		}
497 
498 		Flat |= src.Flat;
499 		NoPerspective |= src.NoPerspective;
500 		Centroid |= src.Centroid;
501 		Block |= src.Block;
502 		BufferBlock |= src.BufferBlock;
503 	}
504 
GetConstantInt(uint32_t id)505 	uint32_t SpirvShader::GetConstantInt(uint32_t id)
506 	{
507 		// Slightly hackish access to constants very early in translation.
508 		// General consumption of constants by other instructions should
509 		// probably be just lowered to Reactor.
510 
511 		// TODO: not encountered yet since we only use this for array sizes etc,
512 		// but is possible to construct integer constant 0 via OpConstantNull.
513 		auto insn = defs[id].definition;
514 		assert(insn.opcode() == spv::OpConstant);
515 		assert(getType(insn.word(1)).definition.opcode() == spv::OpTypeInt);
516 		return insn.word(3);
517 	}
518 }
519