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