• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 "SpirvShader.hpp"
16 
17 // If enabled, each instruction will be printed before processing.
18 #define PRINT_EACH_PROCESSED_INSTRUCTION 0
19 
20 #ifdef ENABLE_VK_DEBUGGER
21 
22 #	include "Vulkan/Debug/Context.hpp"
23 #	include "Vulkan/Debug/File.hpp"
24 #	include "Vulkan/Debug/Thread.hpp"
25 #	include "Vulkan/Debug/Variable.hpp"
26 
27 #	include "spirv-tools/ext/OpenCLDebugInfo100.h"
28 #	include "spirv-tools/libspirv.h"
29 
30 #	include <algorithm>
31 
32 namespace {
33 
34 // ArgTy<F>::type resolves to the single argument type of the function F.
35 template<typename F>
36 struct ArgTy
37 {
38 	using type = typename ArgTy<decltype(&F::operator())>::type;
39 };
40 
41 template<typename R, typename C, typename Arg>
42 struct ArgTy<R (C::*)(Arg) const>
43 {
44 	using type = typename std::decay<Arg>::type;
45 };
46 
47 template<typename T>
48 using ArgTyT = typename ArgTy<T>::type;
49 
50 }  // anonymous namespace
51 
52 namespace spvtools {
53 
54 // Function implemented in third_party/SPIRV-Tools/source/disassemble.cpp
55 // but with no public header.
56 // This is a C++ function, so the name is mangled, and signature changes will
57 // result in a linker error instead of runtime signature mismatches.
58 extern std::string spvInstructionBinaryToText(const spv_target_env env,
59                                               const uint32_t *inst_binary,
60                                               const size_t inst_word_count,
61                                               const uint32_t *binary,
62                                               const size_t word_count,
63                                               const uint32_t options);
64 
65 }  // namespace spvtools
66 
67 namespace {
68 
69 const char *laneNames[] = { "Lane 0", "Lane 1", "Lane 2", "Lane 3" };
70 static_assert(sizeof(laneNames) / sizeof(laneNames[0]) == sw::SIMD::Width,
71               "laneNames must have SIMD::Width entries");
72 
73 template<typename T>
tostring(const T & s)74 std::string tostring(const T &s)
75 {
76 	return std::to_string(s);
77 }
tostring(char * s)78 std::string tostring(char *s)
79 {
80 	return s;
81 }
tostring(const char * s)82 std::string tostring(const char *s)
83 {
84 	return s;
85 }
tostring(sw::SpirvShader::Object::ID id)86 std::string tostring(sw::SpirvShader::Object::ID id)
87 {
88 	return "%" + std::to_string(id.value());
89 }
90 
91 ////////////////////////////////////////////////////////////////////////////////
92 // OpenCL.Debug.100 data structures
93 ////////////////////////////////////////////////////////////////////////////////
94 namespace debug {
95 
96 struct Member;
97 
98 struct Object
99 {
100 	enum class Kind
101 	{
102 		Object,
103 		Declare,
104 		Expression,
105 		Function,
106 		InlinedAt,
107 		LocalVariable,
108 		Member,
109 		Operation,
110 		Source,
111 		SourceScope,
112 		Value,
113 
114 		// Scopes
115 		CompilationUnit,
116 		LexicalBlock,
117 
118 		// Types
119 		BasicType,
120 		VectorType,
121 		FunctionType,
122 		CompositeType,
123 	};
124 
125 	using ID = sw::SpirvID<Object>;
126 	static constexpr auto KIND = Kind::Object;
Object__anon070631ec0211::debug::Object127 	inline Object(Kind kind)
128 	    : kind(kind)
129 	{}
130 	const Kind kind;
131 
132 	// kindof() returns true iff kind is of this type, or any type deriving from
133 	// this type.
kindof__anon070631ec0211::debug::Object134 	static constexpr bool kindof(Object::Kind kind) { return true; }
135 };
136 
137 template<typename TYPE_, typename BASE, Object::Kind KIND_>
138 struct ObjectImpl : public BASE
139 {
140 	using ID = sw::SpirvID<TYPE_>;
141 	static constexpr auto KIND = KIND_;
142 
ObjectImpl__anon070631ec0211::debug::ObjectImpl143 	ObjectImpl()
144 	    : BASE(KIND)
145 	{}
146 	static_assert(BASE::kindof(KIND), "BASE::kindof() returned false");
147 
148 	// kindof() returns true iff kind is of this type, or any type deriving from
149 	// this type.
kindof__anon070631ec0211::debug::ObjectImpl150 	static constexpr bool kindof(Object::Kind kind) { return kind == KIND; }
151 };
152 
153 template<typename TO, typename FROM>
cast(FROM * obj)154 TO *cast(FROM *obj)
155 {
156 	return (TO::kindof(obj->kind)) ? static_cast<TO *>(obj) : nullptr;
157 }
158 
159 template<typename TO, typename FROM>
cast(const FROM * obj)160 const TO *cast(const FROM *obj)
161 {
162 	return (TO::kindof(obj->kind)) ? static_cast<const TO *>(obj) : nullptr;
163 }
164 
165 struct Scope : public Object
166 {
167 	// Root represents the root stack frame scope.
168 	static const Scope Root;
169 
170 	using ID = sw::SpirvID<Scope>;
Scope__anon070631ec0211::debug::Scope171 	inline Scope(Kind kind)
172 	    : Object(kind)
173 	{}
174 
175 	// kindof() returns true iff kind is of this type, or any type deriving from
176 	// this type.
kindof__anon070631ec0211::debug::Scope177 	static constexpr bool kindof(Kind kind)
178 	{
179 		return kind == Kind::CompilationUnit ||
180 		       kind == Kind::LexicalBlock;
181 	}
182 
183 	struct Source *source = nullptr;
184 };
185 
186 struct Type : public Object
187 {
188 	using ID = sw::SpirvID<Type>;
Type__anon070631ec0211::debug::Type189 	inline Type(Kind kind)
190 	    : Object(kind)
191 	{}
192 
193 	// kindof() returns true iff kind is of this type, or any type deriving from
194 	// this type.
kindof__anon070631ec0211::debug::Type195 	static constexpr bool kindof(Kind kind)
196 	{
197 		return kind == Kind::BasicType ||
198 		       kind == Kind::VectorType ||
199 		       kind == Kind::FunctionType ||
200 		       kind == Kind::CompositeType;
201 	}
202 };
203 
204 struct CompilationUnit : ObjectImpl<CompilationUnit, Scope, Object::Kind::CompilationUnit>
205 {
206 };
207 
208 struct Source : ObjectImpl<Source, Object, Object::Kind::Source>
209 {
210 	spv::SourceLanguage language;
211 	uint32_t version = 0;
212 	std::string file;
213 	std::string source;
214 
215 	std::shared_ptr<vk::dbg::File> dbgFile;
216 };
217 
218 struct BasicType : ObjectImpl<BasicType, Type, Object::Kind::BasicType>
219 {
220 	std::string name;
221 	uint32_t size = 0;  // in bits.
222 	OpenCLDebugInfo100DebugBaseTypeAttributeEncoding encoding = OpenCLDebugInfo100Unspecified;
223 };
224 
225 struct VectorType : ObjectImpl<VectorType, Type, Object::Kind::VectorType>
226 {
227 	Type *base = nullptr;
228 	uint32_t components = 0;
229 };
230 
231 struct FunctionType : ObjectImpl<FunctionType, Type, Object::Kind::FunctionType>
232 {
233 	uint32_t flags = 0;  // OR'd from OpenCLDebugInfo100DebugInfoFlags
234 	Type *returnTy = nullptr;
235 	std::vector<Type *> paramTys;
236 };
237 
238 struct CompositeType : ObjectImpl<CompositeType, Type, Object::Kind::CompositeType>
239 {
240 	std::string name;
241 	OpenCLDebugInfo100DebugCompositeType tag = OpenCLDebugInfo100Class;
242 	Source *source = nullptr;
243 	uint32_t line = 0;
244 	uint32_t column = 0;
245 	Object *parent = nullptr;
246 	std::string linkage;
247 	uint32_t size = 0;   // in bits.
248 	uint32_t flags = 0;  // OR'd from OpenCLDebugInfo100DebugInfoFlags
249 	std::vector<Member *> members;
250 };
251 
252 struct Member : ObjectImpl<Member, Object, Object::Kind::Member>
253 {
254 	std::string name;
255 	Type *type = nullptr;
256 	Source *source = nullptr;
257 	uint32_t line = 0;
258 	uint32_t column = 0;
259 	CompositeType *parent = nullptr;
260 	uint32_t offset = 0;  // in bits
261 	uint32_t size = 0;    // in bits
262 	uint32_t flags = 0;   // OR'd from OpenCLDebugInfo100DebugInfoFlags
263 };
264 
265 struct Function : ObjectImpl<Function, Object, Object::Kind::Function>
266 {
267 	std::string name;
268 	FunctionType *type = nullptr;
269 	Source *source = nullptr;
270 	uint32_t line = 0;
271 	uint32_t column = 0;
272 	struct LexicalBlock *parent = nullptr;
273 	std::string linkage;
274 	uint32_t flags = 0;  // OR'd from OpenCLDebugInfo100DebugInfoFlags
275 	uint32_t scopeLine = 0;
276 	sw::SpirvShader::Function::ID function;
277 };
278 
279 struct LexicalBlock : ObjectImpl<LexicalBlock, Scope, Object::Kind::LexicalBlock>
280 {
281 	uint32_t line = 0;
282 	uint32_t column = 0;
283 	Scope *parent = nullptr;
284 	std::string name;
285 	Function *function = nullptr;
286 };
287 
288 struct InlinedAt : ObjectImpl<InlinedAt, Object, Object::Kind::InlinedAt>
289 {
290 	uint32_t line = 0;
291 	Scope *scope = nullptr;
292 	InlinedAt *inlined = nullptr;
293 };
294 
295 struct SourceScope : ObjectImpl<SourceScope, Object, Object::Kind::SourceScope>
296 {
297 	LexicalBlock *scope = nullptr;
298 	InlinedAt *inlinedAt = nullptr;
299 };
300 
301 struct LocalVariable : ObjectImpl<LocalVariable, Object, Object::Kind::LocalVariable>
302 {
303 	static constexpr uint32_t NoArg = ~uint32_t(0);
304 
305 	std::string name;
306 	Type *type = nullptr;
307 	Source *source = nullptr;
308 	uint32_t line = 0;
309 	uint32_t column = 0;
310 	Scope *parent = nullptr;
311 	uint32_t arg = NoArg;
312 };
313 
314 struct Operation : ObjectImpl<Operation, Object, Object::Kind::Operation>
315 {
316 	uint32_t opcode = 0;
317 	std::vector<uint32_t> operands;
318 };
319 
320 struct Expression : ObjectImpl<Expression, Object, Object::Kind::Expression>
321 {
322 	std::vector<Operation *> operations;
323 };
324 
325 struct Declare : ObjectImpl<Declare, Object, Object::Kind::Declare>
326 {
327 	LocalVariable *local = nullptr;
328 	sw::SpirvShader::Object::ID variable;
329 	Expression *expression = nullptr;
330 };
331 
332 struct Value : ObjectImpl<Value, Object, Object::Kind::Value>
333 {
334 	LocalVariable *local = nullptr;
335 	sw::SpirvShader::Object::ID variable;
336 	Expression *expression = nullptr;
337 	std::vector<uint32_t> indexes;
338 };
339 
340 const Scope Scope::Root = CompilationUnit{};
341 
342 }  // namespace debug
343 }  // anonymous namespace
344 
345 namespace rr {
346 
347 ////////////////////////////////////////////////////////////////////////////////
348 // rr::CToReactor<T> specializations.
349 ////////////////////////////////////////////////////////////////////////////////
350 template<typename T>
351 struct CToReactor<sw::SpirvID<T>>
352 {
353 	using type = rr::Int;
castrr::CToReactor354 	static rr::Int cast(sw::SpirvID<T> id) { return rr::Int(id.value()); }
355 };
356 
357 template<typename T>
358 struct CToReactor<vk::dbg::ID<T>>
359 {
360 	using type = rr::Int;
castrr::CToReactor361 	static rr::Int cast(vk::dbg::ID<T> id) { return rr::Int(id.value()); }
362 };
363 
364 }  // namespace rr
365 
366 namespace sw {
367 
368 ////////////////////////////////////////////////////////////////////////////////
369 // sw::SpirvShader::Impl::Debugger
370 //
371 // Private struct holding debugger information for the SpirvShader.
372 ////////////////////////////////////////////////////////////////////////////////
373 struct SpirvShader::Impl::Debugger
374 {
375 	class Group;
376 	class State;
377 
378 	enum class Pass
379 	{
380 		Define,
381 		Emit
382 	};
383 
384 	void process(const SpirvShader *shader, const InsnIterator &insn, EmitState *state, Pass pass);
385 
386 	void setPosition(EmitState *state, const std::string &path, uint32_t line, uint32_t column);
387 
388 	// exposeVariable exposes the variable with the given ID to the debugger
389 	// using the specified key.
390 	template<typename Key>
391 	void exposeVariable(
392 	    const SpirvShader *shader,
393 	    const Key &key,
394 	    const debug::Scope *scope,
395 	    const debug::Type *type,
396 	    Object::ID id,
397 	    EmitState *state) const;
398 
399 	// exposeVariable exposes the variable with the given ID to the
400 	// debugger under the specified group, for the specified SIMD lane.
401 	template<typename Key>
402 	void exposeVariable(
403 	    const SpirvShader *shader,
404 	    const Group &group,
405 	    int lane,
406 	    const Key &key,
407 	    const debug::Type *type,
408 	    Object::ID id,
409 	    EmitState *state,
410 	    int wordOffset = 0) const;
411 
412 	std::shared_ptr<vk::dbg::Context> ctx;
413 	std::shared_ptr<vk::dbg::File> spirvFile;
414 	std::unordered_map<const void *, int> spirvLineMappings;  // instruction pointer to line
415 	std::unordered_map<const void *, Object::ID> results;     // instruction pointer to result ID
416 
417 private:
418 	// add() registers the debug object with the given id.
419 	template<typename ID, typename T>
420 	void add(ID id, T *);
421 
422 	// get() returns the debug object with the given id.
423 	// The object must exist and be of type (or derive from type) T.
424 	template<typename T>
425 	T *get(SpirvID<T> id) const;
426 
427 	// use get() and add() to access this
428 	std::unordered_map<debug::Object::ID, std::unique_ptr<debug::Object>> objects;
429 
430 	std::unordered_map<std::string, vk::dbg::File::ID> fileIDs;
431 
432 	// defineOrEmit() when called in Pass::Define, creates and stores a
433 	// zero-initialized object into the Debugger::objects map using the
434 	// object identifier held by second instruction operand.
435 	// When called in Pass::Emit, defineOrEmit() calls the function F with the
436 	// previously-built object.
437 	//
438 	// F must be a function with the signature:
439 	//   void(OBJECT_TYPE *)
440 	//
441 	// The object type is automatically inferred from the function signature.
442 	template<typename F, typename T = typename std::remove_pointer<ArgTyT<F>>::type>
443 	void defineOrEmit(InsnIterator insn, Pass pass, F &&emit);
444 };
445 
446 ////////////////////////////////////////////////////////////////////////////////
447 // sw::SpirvShader::Impl::Debugger::State
448 //
449 // State holds the runtime data structures for the shader debug session.
450 ////////////////////////////////////////////////////////////////////////////////
451 class SpirvShader::Impl::Debugger::State
452 {
453 public:
454 	static State *create(const Debugger *debugger, const char *name);
455 	static void destroy(State *);
456 
457 	State(const Debugger *debugger, const char *stackBase, vk::dbg::Context::Lock &lock);
458 	~State();
459 
460 	void enter(vk::dbg::Context::Lock &lock, const char *name);
461 	void exit();
462 	void updateActiveLaneMask(int lane, bool enabled);
463 	void update(vk::dbg::File::ID file, int line, int column);
464 	void createScope(const debug::Scope *);
465 	void setScope(debug::SourceScope *newScope);
466 
467 	vk::dbg::VariableContainer *hovers(const debug::Scope *);
468 	vk::dbg::VariableContainer *localsLane(const debug::Scope *, int lane);
469 	vk::dbg::VariableContainer *builtinsLane(int lane);
470 
471 	template<typename K>
472 	vk::dbg::VariableContainer *group(vk::dbg::VariableContainer *vc, K key);
473 
474 	template<typename K, typename V>
475 	void putVal(vk::dbg::VariableContainer *vc, K key, V value);
476 
477 	template<typename K, typename V>
478 	void putRef(vk::dbg::VariableContainer *vc, K key, V *ptr);
479 
480 	// Scopes holds pointers to the vk::dbg::Scopes for local variables, hover
481 	// variables and the locals indexed by SIMD lane.
482 	struct Scopes
483 	{
484 		std::shared_ptr<vk::dbg::Scope> locals;
485 		std::shared_ptr<vk::dbg::Scope> hovers;
486 		std::array<std::shared_ptr<vk::dbg::VariableContainer>, sw::SIMD::Width> localsByLane;
487 	};
488 
489 	// getScopes() returns the Scopes object for the given debug::Scope.
490 	const Scopes &getScopes(const debug::Scope *scope);
491 
492 	const Debugger *debugger;
493 	const std::shared_ptr<vk::dbg::Thread> thread;
494 	std::unordered_map<const debug::Scope *, Scopes> scopes;
495 	Scopes rootScopes;                                                                        // Scopes for the root stack frame.
496 	std::array<std::shared_ptr<vk::dbg::VariableContainer>, sw::SIMD::Width> builtinsByLane;  // Scopes for builtin varibles (shared by all shader frames).
497 	debug::SourceScope *srcScope = nullptr;                                                   // Current source scope.
498 };
499 
create(const Debugger * debugger,const char * name)500 SpirvShader::Impl::Debugger::State *SpirvShader::Impl::Debugger::State::create(const Debugger *debugger, const char *name)
501 {
502 	auto lock = debugger->ctx->lock();
503 	return new State(debugger, name, lock);
504 }
505 
destroy(State * state)506 void SpirvShader::Impl::Debugger::State::destroy(State *state)
507 {
508 	delete state;
509 }
510 
State(const Debugger * debugger,const char * stackBase,vk::dbg::Context::Lock & lock)511 SpirvShader::Impl::Debugger::State::State(const Debugger *debugger, const char *stackBase, vk::dbg::Context::Lock &lock)
512     : debugger(debugger)
513     , thread(lock.currentThread())
514 {
515 	enter(lock, stackBase);
516 
517 	for(int i = 0; i < sw::SIMD::Width; i++)
518 	{
519 		builtinsByLane[i] = lock.createVariableContainer();
520 	}
521 
522 	thread->update([&](vk::dbg::Frame &frame) {
523 		rootScopes.locals = frame.locals;
524 		rootScopes.hovers = frame.hovers;
525 		for(int i = 0; i < sw::SIMD::Width; i++)
526 		{
527 			auto locals = lock.createVariableContainer();
528 			locals->extend(builtinsByLane[i]);
529 			frame.locals->variables->put(laneNames[i], locals);
530 			rootScopes.localsByLane[i] = locals;
531 		}
532 	});
533 }
534 
~State()535 SpirvShader::Impl::Debugger::State::~State()
536 {
537 	exit();
538 }
539 
enter(vk::dbg::Context::Lock & lock,const char * name)540 void SpirvShader::Impl::Debugger::State::enter(vk::dbg::Context::Lock &lock, const char *name)
541 {
542 	thread->enter(lock, debugger->spirvFile, name);
543 }
544 
exit()545 void SpirvShader::Impl::Debugger::State::exit()
546 {
547 	thread->exit();
548 }
549 
updateActiveLaneMask(int lane,bool enabled)550 void SpirvShader::Impl::Debugger::State::updateActiveLaneMask(int lane, bool enabled)
551 {
552 	rootScopes.localsByLane[lane]->put("enabled", vk::dbg::make_constant(enabled));
553 }
554 
update(vk::dbg::File::ID fileID,int line,int column)555 void SpirvShader::Impl::Debugger::State::update(vk::dbg::File::ID fileID, int line, int column)
556 {
557 	auto file = debugger->ctx->lock().get(fileID);
558 	thread->update([&](vk::dbg::Frame &frame) {
559 		frame.location = { file, line, column };
560 	});
561 }
562 
hovers(const debug::Scope * scope)563 vk::dbg::VariableContainer *SpirvShader::Impl::Debugger::State::hovers(const debug::Scope *scope)
564 {
565 	return getScopes(scope).hovers->variables.get();
566 }
567 
localsLane(const debug::Scope * scope,int i)568 vk::dbg::VariableContainer *SpirvShader::Impl::Debugger::State::localsLane(const debug::Scope *scope, int i)
569 {
570 	return getScopes(scope).localsByLane[i].get();
571 }
572 
builtinsLane(int i)573 vk::dbg::VariableContainer *SpirvShader::Impl::Debugger::State::builtinsLane(int i)
574 {
575 	return builtinsByLane[i].get();
576 }
577 
578 template<typename K>
group(vk::dbg::VariableContainer * vc,K key)579 vk::dbg::VariableContainer *SpirvShader::Impl::Debugger::State::group(vk::dbg::VariableContainer *vc, K key)
580 {
581 	auto out = debugger->ctx->lock().createVariableContainer();
582 	vc->put(tostring(key), out);
583 	return out.get();
584 }
585 
586 template<typename K, typename V>
putVal(vk::dbg::VariableContainer * vc,K key,V value)587 void SpirvShader::Impl::Debugger::State::putVal(vk::dbg::VariableContainer *vc, K key, V value)
588 {
589 	vc->put(tostring(key), vk::dbg::make_constant(value));
590 }
591 
592 template<typename K, typename V>
putRef(vk::dbg::VariableContainer * vc,K key,V * ptr)593 void SpirvShader::Impl::Debugger::State::putRef(vk::dbg::VariableContainer *vc, K key, V *ptr)
594 {
595 	vc->put(tostring(key), vk::dbg::make_reference(*ptr));
596 }
597 
createScope(const debug::Scope * spirvScope)598 void SpirvShader::Impl::Debugger::State::createScope(const debug::Scope *spirvScope)
599 {
600 	ASSERT(spirvScope != nullptr);
601 
602 	// TODO: Deal with scope nesting.
603 
604 	auto lock = debugger->ctx->lock();
605 	Scopes s = {};
606 	s.locals = lock.createScope(spirvScope->source->dbgFile);
607 	s.hovers = lock.createScope(spirvScope->source->dbgFile);
608 	for(int i = 0; i < sw::SIMD::Width; i++)
609 	{
610 		auto locals = lock.createVariableContainer();
611 		locals->extend(builtinsByLane[i]);
612 		s.localsByLane[i] = locals;
613 		s.locals->variables->put(laneNames[i], locals);
614 	}
615 	scopes.emplace(spirvScope, std::move(s));
616 }
617 
setScope(debug::SourceScope * newSrcScope)618 void SpirvShader::Impl::Debugger::State::setScope(debug::SourceScope *newSrcScope)
619 {
620 	auto oldSrcScope = srcScope;
621 	if(oldSrcScope == newSrcScope) { return; }
622 	srcScope = newSrcScope;
623 
624 	auto lock = debugger->ctx->lock();
625 	auto thread = lock.currentThread();
626 
627 	debug::Function *oldFunction = oldSrcScope ? oldSrcScope->scope->function : nullptr;
628 	debug::Function *newFunction = newSrcScope ? newSrcScope->scope->function : nullptr;
629 
630 	if(oldFunction != newFunction)
631 	{
632 		if(oldFunction) { thread->exit(); }
633 		if(newFunction) { thread->enter(lock, newFunction->source->dbgFile, newFunction->name); }
634 	}
635 
636 	auto dbgScope = getScopes(srcScope->scope);
637 	thread->update([&](vk::dbg::Frame &frame) {
638 		frame.locals = dbgScope.locals;
639 		frame.hovers = dbgScope.hovers;
640 	});
641 }
642 
getScopes(const debug::Scope * scope)643 const SpirvShader::Impl::Debugger::State::Scopes &SpirvShader::Impl::Debugger::State::getScopes(const debug::Scope *scope)
644 {
645 	if(scope == &debug::Scope::Root)
646 	{
647 		return rootScopes;
648 	}
649 
650 	auto dbgScopeIt = scopes.find(scope);
651 	ASSERT_MSG(dbgScopeIt != scopes.end(), "createScope() not called for debug::Scope %p", scope);
652 	return dbgScopeIt->second;
653 }
654 
655 ////////////////////////////////////////////////////////////////////////////////
656 // sw::SpirvShader::Impl::Debugger::Group
657 //
658 // This provides a convenient C++ interface for adding debugger values to
659 // VariableContainers.
660 ////////////////////////////////////////////////////////////////////////////////
661 class SpirvShader::Impl::Debugger::Group
662 {
663 public:
664 	using Ptr = rr::Pointer<rr::Byte>;
665 
666 	static Group hovers(Ptr state, const debug::Scope *scope);
667 	static Group locals(Ptr state, const debug::Scope *scope);
668 	static Group localsLane(Ptr state, const debug::Scope *scope, int lane);
669 	static Group builtinsLane(Ptr state, int lane);
670 
671 	Group(Ptr state, Ptr group);
672 
673 	template<typename K, typename RK>
674 	Group group(RK key) const;
675 
676 	template<typename K, typename V, typename RK, typename RV>
677 	void put(RK key, RV value) const;
678 
679 	template<typename K, typename V, typename RK>
680 	void putRef(RK key, RValue<Pointer<Byte>> ref) const;
681 
682 	template<typename K, typename V, typename RK, typename RV>
683 	void put(RK key, RV x, RV y) const;
684 
685 	template<typename K, typename V, typename RK, typename RV>
686 	void put(RK key, RV x, RV y, RV z) const;
687 
688 	template<typename K, typename V, typename RK, typename RV>
689 	void put(RK key, RV x, RV y, RV z, RV w) const;
690 
691 	template<typename K, typename V, typename VEC>
692 	void putVec3(K key, const VEC &v) const;
693 
694 private:
695 	Ptr state;
696 	Ptr ptr;
697 };
698 
699 SpirvShader::Impl::Debugger::Group
hovers(Ptr state,const debug::Scope * scope)700 SpirvShader::Impl::Debugger::Group::hovers(Ptr state, const debug::Scope *scope)
701 {
702 	return Group(state, rr::Call(&State::hovers, state, scope));
703 }
704 
705 SpirvShader::Impl::Debugger::Group
localsLane(Ptr state,const debug::Scope * scope,int lane)706 SpirvShader::Impl::Debugger::Group::localsLane(Ptr state, const debug::Scope *scope, int lane)
707 {
708 	return Group(state, rr::Call(&State::localsLane, state, scope, lane));
709 }
710 
711 SpirvShader::Impl::Debugger::Group
builtinsLane(Ptr state,int lane)712 SpirvShader::Impl::Debugger::Group::builtinsLane(Ptr state, int lane)
713 {
714 	return Group(state, rr::Call(&State::builtinsLane, state, lane));
715 }
716 
Group(Ptr state,Ptr group)717 SpirvShader::Impl::Debugger::Group::Group(Ptr state, Ptr group)
718     : state(state)
719     , ptr(group)
720 {}
721 
722 template<typename K, typename RK>
group(RK key) const723 SpirvShader::Impl::Debugger::Group SpirvShader::Impl::Debugger::Group::group(RK key) const
724 {
725 	return Group(state, rr::Call(&State::group<K>, state, ptr, key));
726 }
727 
728 template<typename K, typename V, typename RK, typename RV>
put(RK key,RV value) const729 void SpirvShader::Impl::Debugger::Group::put(RK key, RV value) const
730 {
731 	rr::Call(&State::putVal<K, V>, state, ptr, key, value);
732 }
733 
734 template<typename K, typename V, typename RK>
putRef(RK key,RValue<Pointer<Byte>> ref) const735 void SpirvShader::Impl::Debugger::Group::putRef(RK key, RValue<Pointer<Byte>> ref) const
736 {
737 	rr::Call(&State::putRef<K, V>, state, ptr, key, ref);
738 }
739 
740 template<typename K, typename V, typename RK, typename RV>
put(RK key,RV x,RV y) const741 void SpirvShader::Impl::Debugger::Group::put(RK key, RV x, RV y) const
742 {
743 	auto vec = group<K>(key);
744 	vec.template put<const char *, V>("x", x);
745 	vec.template put<const char *, V>("y", y);
746 }
747 
748 template<typename K, typename V, typename RK, typename RV>
put(RK key,RV x,RV y,RV z) const749 void SpirvShader::Impl::Debugger::Group::put(RK key, RV x, RV y, RV z) const
750 {
751 	auto vec = group<K>(key);
752 	vec.template put<const char *, V>("x", x);
753 	vec.template put<const char *, V>("y", y);
754 	vec.template put<const char *, V>("z", z);
755 }
756 
757 template<typename K, typename V, typename RK, typename RV>
put(RK key,RV x,RV y,RV z,RV w) const758 void SpirvShader::Impl::Debugger::Group::put(RK key, RV x, RV y, RV z, RV w) const
759 {
760 	auto vec = group<K>(key);
761 	vec.template put<const char *, V>("x", x);
762 	vec.template put<const char *, V>("y", y);
763 	vec.template put<const char *, V>("z", z);
764 	vec.template put<const char *, V>("w", w);
765 }
766 
767 template<typename K, typename V, typename VEC>
putVec3(K key,const VEC & v) const768 void SpirvShader::Impl::Debugger::Group::putVec3(K key, const VEC &v) const
769 {
770 	auto vec = group<K>(key);
771 	vec.template put<const char *, V>("x", Extract(v, 0));
772 	vec.template put<const char *, V>("y", Extract(v, 1));
773 	vec.template put<const char *, V>("z", Extract(v, 2));
774 }
775 
776 ////////////////////////////////////////////////////////////////////////////////
777 // sw::SpirvShader::Impl::Debugger methods
778 ////////////////////////////////////////////////////////////////////////////////
779 template<typename F, typename T>
defineOrEmit(InsnIterator insn,Pass pass,F && emit)780 void SpirvShader::Impl::Debugger::defineOrEmit(InsnIterator insn, Pass pass, F &&emit)
781 {
782 	auto id = SpirvID<T>(insn.word(2));
783 	switch(pass)
784 	{
785 		case Pass::Define:
786 			add(id, new T());
787 			break;
788 		case Pass::Emit:
789 			emit(get<T>(id));
790 			break;
791 	}
792 }
793 
process(const SpirvShader * shader,const InsnIterator & insn,EmitState * state,Pass pass)794 void SpirvShader::Impl::Debugger::process(const SpirvShader *shader, const InsnIterator &insn, EmitState *state, Pass pass)
795 {
796 	auto dbg = shader->impl.debugger;
797 	auto extInstIndex = insn.word(4);
798 	switch(extInstIndex)
799 	{
800 		case OpenCLDebugInfo100DebugCompilationUnit:
801 			defineOrEmit(insn, pass, [&](debug::CompilationUnit *cu) {
802 				cu->source = get(debug::Source::ID(insn.word(7)));
803 			});
804 			break;
805 		case OpenCLDebugInfo100DebugTypeBasic:
806 			defineOrEmit(insn, pass, [&](debug::BasicType *type) {
807 				type->name = shader->getString(insn.word(5));
808 				type->size = shader->GetConstScalarInt(insn.word(6));
809 				type->encoding = static_cast<OpenCLDebugInfo100DebugBaseTypeAttributeEncoding>(insn.word(7));
810 			});
811 			break;
812 		case OpenCLDebugInfo100DebugTypeVector:
813 			defineOrEmit(insn, pass, [&](debug::VectorType *type) {
814 				type->base = get(debug::Type::ID(insn.word(5)));
815 				type->components = insn.word(6);
816 			});
817 			break;
818 		case OpenCLDebugInfo100DebugTypeFunction:
819 			defineOrEmit(insn, pass, [&](debug::FunctionType *type) {
820 				type->flags = insn.word(5);
821 				type->returnTy = get(debug::Type::ID(insn.word(6)));
822 				for(uint32_t i = 7; i < insn.wordCount(); i++)
823 				{
824 					type->paramTys.push_back(get(debug::Type::ID(insn.word(i))));
825 				}
826 			});
827 			break;
828 		case OpenCLDebugInfo100DebugTypeComposite:
829 			defineOrEmit(insn, pass, [&](debug::CompositeType *type) {
830 				type->name = shader->getString(insn.word(5));
831 				type->tag = static_cast<OpenCLDebugInfo100DebugCompositeType>(insn.word(6));
832 				type->source = get(debug::Source::ID(insn.word(7)));
833 				type->line = insn.word(8);
834 				type->column = insn.word(9);
835 				type->parent = get(debug::Object::ID(insn.word(10)));
836 				type->linkage = shader->getString(insn.word(11));
837 				type->size = shader->GetConstScalarInt(insn.word(12));
838 				type->flags = insn.word(13);
839 				for(uint32_t i = 14; i < insn.wordCount(); i++)
840 				{
841 					auto obj = get(debug::Object::ID(insn.word(i)));
842 					if(auto member = debug::cast<debug::Member>(obj))  // Can also be Function or TypeInheritance, which we don't care about.
843 					{
844 						type->members.push_back(member);
845 					}
846 				}
847 			});
848 			break;
849 		case OpenCLDebugInfo100DebugTypeMember:
850 			defineOrEmit(insn, pass, [&](debug::Member *member) {
851 				member->name = shader->getString(insn.word(5));
852 				member->type = get(debug::Type::ID(insn.word(6)));
853 				member->source = get(debug::Source::ID(insn.word(7)));
854 				member->line = insn.word(8);
855 				member->column = insn.word(9);
856 				member->parent = get(debug::CompositeType::ID(insn.word(10)));
857 				member->offset = shader->GetConstScalarInt(insn.word(11));
858 				member->size = shader->GetConstScalarInt(insn.word(12));
859 				member->flags = insn.word(13);
860 			});
861 			break;
862 		case OpenCLDebugInfo100DebugFunction:
863 			defineOrEmit(insn, pass, [&](debug::Function *func) {
864 				func->name = shader->getString(insn.word(5));
865 				func->type = get(debug::FunctionType::ID(insn.word(6)));
866 				func->source = get(debug::Source::ID(insn.word(7)));
867 				func->line = insn.word(8);
868 				func->column = insn.word(9);
869 				func->parent = get(debug::LexicalBlock::ID(insn.word(10)));
870 				func->linkage = shader->getString(insn.word(11));
871 				func->flags = insn.word(12);
872 				func->scopeLine = insn.word(13);
873 				func->function = Function::ID(insn.word(14));
874 				// declaration: word(13)
875 
876 				func->parent->function = func;
877 			});
878 			break;
879 		case OpenCLDebugInfo100DebugLexicalBlock:
880 			defineOrEmit(insn, pass, [&](debug::LexicalBlock *scope) {
881 				scope->source = get(debug::Source::ID(insn.word(5)));
882 				scope->line = insn.word(6);
883 				scope->column = insn.word(7);
884 				scope->parent = get(debug::Scope::ID(insn.word(8)));
885 				if(insn.wordCount() > 9)
886 				{
887 					scope->name = shader->getString(insn.word(9));
888 				}
889 
890 				// TODO: We're creating scopes per-shader invocation.
891 				// This is all really static information, and should only be created
892 				// once *per program*.
893 				rr::Call(&State::createScope, state->routine->dbgState, scope);
894 			});
895 			break;
896 		case OpenCLDebugInfo100DebugScope:
897 			defineOrEmit(insn, pass, [&](debug::SourceScope *ss) {
898 				ss->scope = get(debug::LexicalBlock::ID(insn.word(5)));
899 				if(insn.wordCount() > 6)
900 				{
901 					ss->inlinedAt = get(debug::InlinedAt::ID(insn.word(6)));
902 				}
903 
904 				rr::Call(&State::setScope, state->routine->dbgState, ss);
905 			});
906 			break;
907 		case OpenCLDebugInfo100DebugNoScope:
908 			break;
909 		case OpenCLDebugInfo100DebugLocalVariable:
910 			defineOrEmit(insn, pass, [&](debug::LocalVariable *var) {
911 				var->name = shader->getString(insn.word(5));
912 				var->type = get(debug::Type::ID(insn.word(6)));
913 				var->source = get(debug::Source::ID(insn.word(7)));
914 				var->line = insn.word(8);
915 				var->column = insn.word(9);
916 				var->parent = get(debug::Scope::ID(insn.word(10)));
917 				if(insn.wordCount() > 11)
918 				{
919 					var->arg = insn.word(11);
920 				}
921 			});
922 			break;
923 		case OpenCLDebugInfo100DebugDeclare:
924 			defineOrEmit(insn, pass, [&](debug::Declare *decl) {
925 				decl->local = get(debug::LocalVariable::ID(insn.word(5)));
926 				decl->variable = Object::ID(insn.word(6));
927 				decl->expression = get(debug::Expression::ID(insn.word(7)));
928 				exposeVariable(
929 				    shader,
930 				    decl->local->name.c_str(),
931 				    decl->local->parent,
932 				    decl->local->type,
933 				    decl->variable,
934 				    state);
935 			});
936 			break;
937 		case OpenCLDebugInfo100DebugValue:
938 			defineOrEmit(insn, pass, [&](debug::Value *value) {
939 				value->local = get(debug::LocalVariable::ID(insn.word(5)));
940 				value->variable = Object::ID(insn.word(6));
941 				value->expression = get(debug::Expression::ID(insn.word(7)));
942 				for(uint32_t i = 8; i < insn.wordCount(); i++)
943 				{
944 					value->indexes.push_back(insn.word(i));
945 				}
946 			});
947 			break;
948 		case OpenCLDebugInfo100DebugExpression:
949 			defineOrEmit(insn, pass, [&](debug::Expression *expr) {
950 				for(uint32_t i = 5; i < insn.wordCount(); i++)
951 				{
952 					expr->operations.push_back(get(debug::Operation::ID(insn.word(i))));
953 				}
954 			});
955 			break;
956 		case OpenCLDebugInfo100DebugSource:
957 			defineOrEmit(insn, pass, [&](debug::Source *source) {
958 				source->file = shader->getString(insn.word(5));
959 				if(insn.wordCount() > 6)
960 				{
961 					source->source = shader->getString(insn.word(6));
962 				}
963 
964 				auto file = dbg->ctx->lock().createVirtualFile(source->file.c_str(), source->source.c_str());
965 				source->dbgFile = file;
966 				fileIDs.emplace(source->file.c_str(), file->id);
967 			});
968 			break;
969 		default:
970 			UNSUPPORTED("Unsupported OpenCLDebugInfo100 instruction %d", int(extInstIndex));
971 	}
972 }
973 
setPosition(EmitState * state,const std::string & path,uint32_t line,uint32_t column)974 void SpirvShader::Impl::Debugger::setPosition(EmitState *state, const std::string &path, uint32_t line, uint32_t column)
975 {
976 	auto it = fileIDs.find(path);
977 	if(it != fileIDs.end())
978 	{
979 		rr::Call(&State::update, state->routine->dbgState, it->second, line, column);
980 	}
981 }
982 
983 template<typename ID, typename T>
add(ID id,T * obj)984 void SpirvShader::Impl::Debugger::add(ID id, T *obj)
985 {
986 	auto added = objects.emplace(debug::Object::ID(id.value()), obj).second;
987 	ASSERT_MSG(added, "Debug object with %d already exists", id.value());
988 }
989 
990 template<typename T>
get(SpirvID<T> id) const991 T *SpirvShader::Impl::Debugger::get(SpirvID<T> id) const
992 {
993 	auto it = objects.find(debug::Object::ID(id.value()));
994 	ASSERT_MSG(it != objects.end(), "Unknown debug object %d", id.value());
995 	auto ptr = debug::cast<T>(it->second.get());
996 	ASSERT_MSG(ptr, "Debug object %d is not of the correct type. Got: %d, want: %d",
997 	           id.value(), int(it->second->kind), int(T::KIND));
998 	return ptr;
999 }
1000 
1001 template<typename Key>
exposeVariable(const SpirvShader * shader,const Key & key,const debug::Scope * scope,const debug::Type * type,Object::ID id,EmitState * state) const1002 void SpirvShader::Impl::Debugger::exposeVariable(
1003     const SpirvShader *shader,
1004     const Key &key,
1005     const debug::Scope *scope,
1006     const debug::Type *type,
1007     Object::ID id,
1008     EmitState *state) const
1009 {
1010 	auto dbgState = state->routine->dbgState;
1011 	auto hover = Group::hovers(dbgState, scope).group<Key>(key);
1012 	for(int lane = 0; lane < SIMD::Width; lane++)
1013 	{
1014 		exposeVariable(shader, Group::localsLane(dbgState, scope, lane), lane, key, type, id, state);
1015 		exposeVariable(shader, hover, lane, laneNames[lane], type, id, state);
1016 	}
1017 }
1018 
1019 template<typename Key>
exposeVariable(const SpirvShader * shader,const Group & group,int l,const Key & key,const debug::Type * type,Object::ID id,EmitState * state,int wordOffset) const1020 void SpirvShader::Impl::Debugger::exposeVariable(
1021     const SpirvShader *shader,
1022     const Group &group,
1023     int l,
1024     const Key &key,
1025     const debug::Type *type,
1026     Object::ID id,
1027     EmitState *state,
1028     int wordOffset /* = 0 */) const
1029 {
1030 	if(type != nullptr)
1031 	{
1032 		if(auto ty = debug::cast<debug::BasicType>(type))
1033 		{
1034 			auto &obj = shader->getObject(id);
1035 			SIMD::Int val;
1036 			switch(obj.kind)
1037 			{
1038 				case Object::Kind::InterfaceVariable:
1039 				case Object::Kind::Pointer:
1040 				{
1041 					auto ptr = shader->GetPointerToData(id, 0, state) + sizeof(uint32_t) * wordOffset;
1042 					auto &ptrTy = shader->getType(obj.type);
1043 					if(IsStorageInterleavedByLane(ptrTy.storageClass))
1044 					{
1045 						ptr = InterleaveByLane(ptr);
1046 					}
1047 					auto addr = &ptr.base[Extract(ptr.offsets(), l)];
1048 					switch(ty->encoding)
1049 					{
1050 						case OpenCLDebugInfo100Address:
1051 							// TODO: This function takes a SIMD vector, and pointers cannot
1052 							// be held in them.
1053 							break;
1054 						case OpenCLDebugInfo100Boolean:
1055 							group.putRef<Key, bool>(key, addr);
1056 							break;
1057 						case OpenCLDebugInfo100Float:
1058 							group.putRef<Key, float>(key, addr);
1059 							break;
1060 						case OpenCLDebugInfo100Signed:
1061 							group.putRef<Key, int>(key, addr);
1062 							break;
1063 						case OpenCLDebugInfo100SignedChar:
1064 							group.putRef<Key, int8_t>(key, addr);
1065 							break;
1066 						case OpenCLDebugInfo100Unsigned:
1067 							group.putRef<Key, unsigned int>(key, addr);
1068 							break;
1069 						case OpenCLDebugInfo100UnsignedChar:
1070 							group.putRef<Key, uint8_t>(key, addr);
1071 							break;
1072 						default:
1073 							break;
1074 					}
1075 				}
1076 				break;
1077 				case Object::Kind::Constant:
1078 				case Object::Kind::Intermediate:
1079 				{
1080 					auto val = GenericValue(shader, state, id).Int(wordOffset);
1081 
1082 					switch(ty->encoding)
1083 					{
1084 						case OpenCLDebugInfo100Address:
1085 							// TODO: This function takes a SIMD vector, and pointers cannot
1086 							// be held in them.
1087 							break;
1088 						case OpenCLDebugInfo100Boolean:
1089 							group.put<Key, bool>(key, Extract(val, l) != 0);
1090 							break;
1091 						case OpenCLDebugInfo100Float:
1092 							group.put<Key, float>(key, Extract(As<SIMD::Float>(val), l));
1093 							break;
1094 						case OpenCLDebugInfo100Signed:
1095 							group.put<Key, int>(key, Extract(val, l));
1096 							break;
1097 						case OpenCLDebugInfo100SignedChar:
1098 							group.put<Key, int8_t>(key, SByte(Extract(val, l)));
1099 							break;
1100 						case OpenCLDebugInfo100Unsigned:
1101 							group.put<Key, unsigned int>(key, Extract(val, l));
1102 							break;
1103 						case OpenCLDebugInfo100UnsignedChar:
1104 							group.put<Key, uint8_t>(key, Byte(Extract(val, l)));
1105 							break;
1106 						default:
1107 							break;
1108 					}
1109 				}
1110 				break;
1111 				default:
1112 					break;
1113 			}
1114 			return;
1115 		}
1116 		else if(auto ty = debug::cast<debug::VectorType>(type))
1117 		{
1118 			auto elWords = 1;  // Currently vector elements must only be basic types, 32-bit wide
1119 			auto elTy = ty->base;
1120 			auto vecGroup = group.group<Key>(key);
1121 			switch(ty->components)
1122 			{
1123 				case 1:
1124 					exposeVariable(shader, vecGroup, l, "x", elTy, id, state, wordOffset + 0 * elWords);
1125 					break;
1126 				case 2:
1127 					exposeVariable(shader, vecGroup, l, "x", elTy, id, state, wordOffset + 0 * elWords);
1128 					exposeVariable(shader, vecGroup, l, "y", elTy, id, state, wordOffset + 1 * elWords);
1129 					break;
1130 				case 3:
1131 					exposeVariable(shader, vecGroup, l, "x", elTy, id, state, wordOffset + 0 * elWords);
1132 					exposeVariable(shader, vecGroup, l, "y", elTy, id, state, wordOffset + 1 * elWords);
1133 					exposeVariable(shader, vecGroup, l, "z", elTy, id, state, wordOffset + 2 * elWords);
1134 					break;
1135 				case 4:
1136 					exposeVariable(shader, vecGroup, l, "x", elTy, id, state, wordOffset + 0 * elWords);
1137 					exposeVariable(shader, vecGroup, l, "y", elTy, id, state, wordOffset + 1 * elWords);
1138 					exposeVariable(shader, vecGroup, l, "z", elTy, id, state, wordOffset + 2 * elWords);
1139 					exposeVariable(shader, vecGroup, l, "w", elTy, id, state, wordOffset + 3 * elWords);
1140 					break;
1141 				default:
1142 					for(uint32_t i = 0; i < ty->components; i++)
1143 					{
1144 						exposeVariable(shader, vecGroup, l, std::to_string(i).c_str(), elTy, id, state, wordOffset + i * elWords);
1145 					}
1146 					break;
1147 			}
1148 			return;
1149 		}
1150 		else if(auto ty = debug::cast<debug::CompositeType>(type))
1151 		{
1152 			auto objectGroup = group.group<Key>(key);
1153 
1154 			for(auto member : ty->members)
1155 			{
1156 				exposeVariable(shader, objectGroup, l, member->name.c_str(), member->type, id, state, member->offset / 32);
1157 			}
1158 
1159 			return;
1160 		}
1161 	}
1162 
1163 	// No debug type information. Derive from SPIR-V.
1164 	GenericValue val(shader, state, id);
1165 	switch(shader->getType(val.type).opcode())
1166 	{
1167 		case spv::OpTypeInt:
1168 		{
1169 			group.put<Key, int>(key, Extract(val.Int(0), l));
1170 		}
1171 		break;
1172 		case spv::OpTypeFloat:
1173 		{
1174 			group.put<Key, float>(key, Extract(val.Float(0), l));
1175 		}
1176 		break;
1177 		case spv::OpTypeVector:
1178 		{
1179 			auto count = shader->getType(val.type).definition.word(3);
1180 			switch(count)
1181 			{
1182 				case 1:
1183 					group.put<Key, float>(key, Extract(val.Float(0), l));
1184 					break;
1185 				case 2:
1186 					group.put<Key, float>(key, Extract(val.Float(0), l), Extract(val.Float(1), l));
1187 					break;
1188 				case 3:
1189 					group.put<Key, float>(key, Extract(val.Float(0), l), Extract(val.Float(1), l), Extract(val.Float(2), l));
1190 					break;
1191 				case 4:
1192 					group.put<Key, float>(key, Extract(val.Float(0), l), Extract(val.Float(1), l), Extract(val.Float(2), l), Extract(val.Float(3), l));
1193 					break;
1194 				default:
1195 				{
1196 					auto vec = group.group<Key>(key);
1197 					for(uint32_t i = 0; i < count; i++)
1198 					{
1199 						vec.template put<int, float>(i, Extract(val.Float(i), l));
1200 					}
1201 				}
1202 				break;
1203 			}
1204 		}
1205 		break;
1206 		case spv::OpTypePointer:
1207 		{
1208 			auto objectTy = shader->getType(shader->getObject(id).type);
1209 			bool interleavedByLane = IsStorageInterleavedByLane(objectTy.storageClass);
1210 			auto ptr = state->getPointer(id);
1211 			auto ptrGroup = group.group<Key>(key);
1212 			shader->VisitMemoryObject(id, [&](const MemoryElement &el) {
1213 				auto p = ptr + el.offset;
1214 				if(interleavedByLane) { p = InterleaveByLane(p); }  // TODO: Interleave once, then add offset?
1215 				auto simd = p.Load<SIMD::Float>(sw::OutOfBoundsBehavior::Nullify, state->activeLaneMask());
1216 				ptrGroup.template put<int, float>(el.index, Extract(simd, l));
1217 			});
1218 		}
1219 		break;
1220 		default:
1221 			break;
1222 	}
1223 }
1224 
1225 ////////////////////////////////////////////////////////////////////////////////
1226 // sw::SpirvShader
1227 ////////////////////////////////////////////////////////////////////////////////
dbgInit(const std::shared_ptr<vk::dbg::Context> & dbgctx)1228 void SpirvShader::dbgInit(const std::shared_ptr<vk::dbg::Context> &dbgctx)
1229 {
1230 	impl.debugger = new Impl::Debugger();
1231 	impl.debugger->ctx = dbgctx;
1232 }
1233 
dbgTerm()1234 void SpirvShader::dbgTerm()
1235 {
1236 	if(impl.debugger)
1237 	{
1238 		delete impl.debugger;
1239 	}
1240 }
1241 
dbgCreateFile()1242 void SpirvShader::dbgCreateFile()
1243 {
1244 	auto dbg = impl.debugger;
1245 	if(!dbg) { return; }
1246 
1247 	int currentLine = 1;
1248 	std::string source;
1249 	for(auto insn : *this)
1250 	{
1251 		auto instruction = spvtools::spvInstructionBinaryToText(
1252 		                       SPV_ENV_VULKAN_1_1,
1253 		                       insn.wordPointer(0),
1254 		                       insn.wordCount(),
1255 		                       insns.data(),
1256 		                       insns.size(),
1257 		                       SPV_BINARY_TO_TEXT_OPTION_NO_HEADER) +
1258 		                   "\n";
1259 		dbg->spirvLineMappings[insn.wordPointer(0)] = currentLine;
1260 		currentLine += std::count(instruction.begin(), instruction.end(), '\n');
1261 		source += instruction;
1262 	}
1263 	std::string name;
1264 	switch(executionModel)
1265 	{
1266 		case spv::ExecutionModelVertex: name = "VertexShader"; break;
1267 		case spv::ExecutionModelFragment: name = "FragmentShader"; break;
1268 		case spv::ExecutionModelGLCompute: name = "ComputeShader"; break;
1269 		default: name = "SPIR-V Shader"; break;
1270 	}
1271 	static std::atomic<int> id = { 0 };
1272 	name += std::to_string(id++) + ".spvasm";
1273 	dbg->spirvFile = dbg->ctx->lock().createVirtualFile(name.c_str(), source.c_str());
1274 }
1275 
dbgBeginEmit(EmitState * state) const1276 void SpirvShader::dbgBeginEmit(EmitState *state) const
1277 {
1278 	auto dbg = impl.debugger;
1279 	if(!dbg) { return; }
1280 
1281 	using Group = Impl::Debugger::Group;
1282 
1283 	auto routine = state->routine;
1284 
1285 	auto type = "SPIR-V";
1286 	switch(executionModel)
1287 	{
1288 		case spv::ExecutionModelVertex: type = "VertexShader"; break;
1289 		case spv::ExecutionModelFragment: type = "FragmentShader"; break;
1290 		case spv::ExecutionModelGLCompute: type = "ComputeShader"; break;
1291 		default: type = "SPIR-V Shader"; break;
1292 	}
1293 	auto dbgState = rr::Call(&Impl::Debugger::State::create, dbg, type);
1294 
1295 	routine->dbgState = dbgState;
1296 
1297 	SetActiveLaneMask(state->activeLaneMask(), state);
1298 
1299 	for(int i = 0; i < SIMD::Width; i++)
1300 	{
1301 		auto builtins = Group::builtinsLane(dbgState, i);
1302 		builtins.put<const char *, int>("subgroupSize", routine->invocationsPerSubgroup);
1303 
1304 		switch(executionModel)
1305 		{
1306 			case spv::ExecutionModelGLCompute:
1307 				builtins.putVec3<const char *, int>("numWorkgroups", routine->numWorkgroups);
1308 				builtins.putVec3<const char *, int>("workgroupID", routine->workgroupID);
1309 				builtins.putVec3<const char *, int>("workgroupSize", routine->workgroupSize);
1310 				builtins.put<const char *, int>("numSubgroups", routine->subgroupsPerWorkgroup);
1311 				builtins.put<const char *, int>("subgroupIndex", routine->subgroupIndex);
1312 
1313 				builtins.put<const char *, int>("globalInvocationId",
1314 				                                rr::Extract(routine->globalInvocationID[0], i),
1315 				                                rr::Extract(routine->globalInvocationID[1], i),
1316 				                                rr::Extract(routine->globalInvocationID[2], i));
1317 				builtins.put<const char *, int>("localInvocationId",
1318 				                                rr::Extract(routine->localInvocationID[0], i),
1319 				                                rr::Extract(routine->localInvocationID[1], i),
1320 				                                rr::Extract(routine->localInvocationID[2], i));
1321 				builtins.put<const char *, int>("localInvocationIndex", rr::Extract(routine->localInvocationIndex, i));
1322 				break;
1323 
1324 			case spv::ExecutionModelFragment:
1325 				builtins.put<const char *, int>("viewIndex", routine->viewID);
1326 				builtins.put<const char *, float>("fragCoord",
1327 				                                  rr::Extract(routine->fragCoord[0], i),
1328 				                                  rr::Extract(routine->fragCoord[1], i),
1329 				                                  rr::Extract(routine->fragCoord[2], i),
1330 				                                  rr::Extract(routine->fragCoord[3], i));
1331 				builtins.put<const char *, float>("pointCoord",
1332 				                                  rr::Extract(routine->pointCoord[0], i),
1333 				                                  rr::Extract(routine->pointCoord[1], i));
1334 				builtins.put<const char *, int>("windowSpacePosition",
1335 				                                rr::Extract(routine->windowSpacePosition[0], i),
1336 				                                rr::Extract(routine->windowSpacePosition[1], i));
1337 				builtins.put<const char *, int>("helperInvocation", rr::Extract(routine->helperInvocation, i));
1338 				break;
1339 
1340 			case spv::ExecutionModelVertex:
1341 				builtins.put<const char *, int>("viewIndex", routine->viewID);
1342 				builtins.put<const char *, int>("instanceIndex", routine->instanceID);
1343 				builtins.put<const char *, int>("vertexIndex",
1344 				                                rr::Extract(routine->vertexIndex, i));
1345 				break;
1346 
1347 			default:
1348 				break;
1349 		}
1350 	}
1351 }
1352 
dbgEndEmit(EmitState * state) const1353 void SpirvShader::dbgEndEmit(EmitState *state) const
1354 {
1355 	auto dbg = impl.debugger;
1356 	if(!dbg) { return; }
1357 
1358 	rr::Call(&Impl::Debugger::State::destroy, state->routine->dbgState);
1359 }
1360 
dbgBeginEmitInstruction(InsnIterator insn,EmitState * state) const1361 void SpirvShader::dbgBeginEmitInstruction(InsnIterator insn, EmitState *state) const
1362 {
1363 #	if PRINT_EACH_PROCESSED_INSTRUCTION
1364 	auto instruction = spvtools::spvInstructionBinaryToText(
1365 	    SPV_ENV_VULKAN_1_1,
1366 	    insn.wordPointer(0),
1367 	    insn.wordCount(),
1368 	    insns.data(),
1369 	    insns.size(),
1370 	    SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1371 	printf("%s\n", instruction.c_str());
1372 #	endif  // PRINT_EACH_PROCESSED_INSTRUCTION
1373 
1374 	if(extensionsImported.count(Extension::OpenCLDebugInfo100) == 0)
1375 	{
1376 		// We're emitting debugger logic for SPIR-V.
1377 		// Only single line step over statement instructions.
1378 		if(IsStatement(insn.opcode()))
1379 		{
1380 			auto dbg = impl.debugger;
1381 			if(!dbg) { return; }
1382 
1383 			auto line = dbg->spirvLineMappings.at(insn.wordPointer(0));
1384 			auto column = 0;
1385 			rr::Call(&Impl::Debugger::State::update, state->routine->dbgState, dbg->spirvFile->id, line, column);
1386 		}
1387 	}
1388 }
1389 
dbgEndEmitInstruction(InsnIterator insn,EmitState * state) const1390 void SpirvShader::dbgEndEmitInstruction(InsnIterator insn, EmitState *state) const
1391 {
1392 	auto dbg = impl.debugger;
1393 	if(!dbg) { return; }
1394 
1395 	auto resIt = dbg->results.find(insn.wordPointer(0));
1396 	if(resIt != dbg->results.end())
1397 	{
1398 		auto id = resIt->second;
1399 		dbgExposeIntermediate(id, state);
1400 	}
1401 }
1402 
dbgExposeIntermediate(Object::ID id,EmitState * state) const1403 void SpirvShader::dbgExposeIntermediate(Object::ID id, EmitState *state) const
1404 {
1405 	auto dbg = impl.debugger;
1406 	if(!dbg) { return; }
1407 
1408 	dbg->exposeVariable(this, id, &debug::Scope::Root, nullptr, id, state);
1409 }
1410 
dbgUpdateActiveLaneMask(RValue<SIMD::Int> mask,EmitState * state) const1411 void SpirvShader::dbgUpdateActiveLaneMask(RValue<SIMD::Int> mask, EmitState *state) const
1412 {
1413 	auto dbg = impl.debugger;
1414 	if(!dbg) { return; }
1415 
1416 	for(int lane = 0; lane < SIMD::Width; lane++)
1417 	{
1418 		rr::Call(&Impl::Debugger::State::updateActiveLaneMask, state->routine->dbgState, lane, rr::Extract(mask, lane) != 0);
1419 	}
1420 }
1421 
dbgDeclareResult(const InsnIterator & insn,Object::ID resultId) const1422 void SpirvShader::dbgDeclareResult(const InsnIterator &insn, Object::ID resultId) const
1423 {
1424 	auto dbg = impl.debugger;
1425 	if(!dbg) { return; }
1426 
1427 	dbg->results.emplace(insn.wordPointer(0), resultId);
1428 }
1429 
EmitLine(InsnIterator insn,EmitState * state) const1430 SpirvShader::EmitResult SpirvShader::EmitLine(InsnIterator insn, EmitState *state) const
1431 {
1432 	if(auto dbg = impl.debugger)
1433 	{
1434 		auto path = getString(insn.word(1));
1435 		auto line = insn.word(2);
1436 		auto column = insn.word(3);
1437 		dbg->setPosition(state, path, line, column);
1438 	}
1439 	return EmitResult::Continue;
1440 }
1441 
DefineOpenCLDebugInfo100(const InsnIterator & insn)1442 void SpirvShader::DefineOpenCLDebugInfo100(const InsnIterator &insn)
1443 {
1444 	auto dbg = impl.debugger;
1445 	if(!dbg) { return; }
1446 
1447 	dbg->process(this, insn, nullptr, Impl::Debugger::Pass::Define);
1448 }
1449 
EmitOpenCLDebugInfo100(InsnIterator insn,EmitState * state) const1450 SpirvShader::EmitResult SpirvShader::EmitOpenCLDebugInfo100(InsnIterator insn, EmitState *state) const
1451 {
1452 	if(auto dbg = impl.debugger)
1453 	{
1454 		dbg->process(this, insn, state, Impl::Debugger::Pass::Emit);
1455 	}
1456 	return EmitResult::Continue;
1457 }
1458 
1459 }  // namespace sw
1460 
1461 #else  // ENABLE_VK_DEBUGGER
1462 
1463 // Stub implementations of the dbgXXX functions.
1464 namespace sw {
1465 
dbgInit(const std::shared_ptr<vk::dbg::Context> & dbgctx)1466 void SpirvShader::dbgInit(const std::shared_ptr<vk::dbg::Context> &dbgctx) {}
dbgTerm()1467 void SpirvShader::dbgTerm() {}
dbgCreateFile()1468 void SpirvShader::dbgCreateFile() {}
dbgBeginEmit(EmitState * state) const1469 void SpirvShader::dbgBeginEmit(EmitState *state) const {}
dbgEndEmit(EmitState * state) const1470 void SpirvShader::dbgEndEmit(EmitState *state) const {}
dbgBeginEmitInstruction(InsnIterator insn,EmitState * state) const1471 void SpirvShader::dbgBeginEmitInstruction(InsnIterator insn, EmitState *state) const {}
dbgEndEmitInstruction(InsnIterator insn,EmitState * state) const1472 void SpirvShader::dbgEndEmitInstruction(InsnIterator insn, EmitState *state) const {}
dbgExposeIntermediate(Object::ID id,EmitState * state) const1473 void SpirvShader::dbgExposeIntermediate(Object::ID id, EmitState *state) const {}
dbgUpdateActiveLaneMask(RValue<SIMD::Int> mask,EmitState * state) const1474 void SpirvShader::dbgUpdateActiveLaneMask(RValue<SIMD::Int> mask, EmitState *state) const {}
dbgDeclareResult(const InsnIterator & insn,Object::ID resultId) const1475 void SpirvShader::dbgDeclareResult(const InsnIterator &insn, Object::ID resultId) const {}
1476 
DefineOpenCLDebugInfo100(const InsnIterator & insn)1477 void SpirvShader::DefineOpenCLDebugInfo100(const InsnIterator &insn) {}
1478 
EmitOpenCLDebugInfo100(InsnIterator insn,EmitState * state) const1479 SpirvShader::EmitResult SpirvShader::EmitOpenCLDebugInfo100(InsnIterator insn, EmitState *state) const
1480 {
1481 	return EmitResult::Continue;
1482 }
1483 
EmitLine(InsnIterator insn,EmitState * state) const1484 SpirvShader::EmitResult SpirvShader::EmitLine(InsnIterator insn, EmitState *state) const
1485 {
1486 	return EmitResult::Continue;
1487 }
1488 
1489 }  // namespace sw
1490 
1491 #endif  // ENABLE_VK_DEBUGGER
1492