1 /*
2 * Copyright 2021 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7 #include "src/sksl/tracing/SkSLDebugTracePriv.h"
8
9 #include "include/core/SkStream.h"
10 #include "include/core/SkTypes.h"
11 #include "src/sksl/ir/SkSLType.h"
12
13 #include <cstdio>
14 #include <cstring>
15 #include <sstream>
16 #include <string>
17
18 namespace SkSL {
19
getSlotComponentSuffix(int slotIndex) const20 std::string DebugTracePriv::getSlotComponentSuffix(int slotIndex) const {
21 const SkSL::SlotDebugInfo& slot = fSlotInfo[slotIndex];
22
23 if (slot.rows > 1) {
24 return "[" + std::to_string(slot.componentIndex / slot.rows) +
25 "][" + std::to_string(slot.componentIndex % slot.rows) +
26 "]";
27 }
28 if (slot.columns > 1) {
29 switch (slot.componentIndex) {
30 case 0: return ".x";
31 case 1: return ".y";
32 case 2: return ".z";
33 case 3: return ".w";
34 default: return "[???]";
35 }
36 }
37 return {};
38 }
39
interpretValueBits(int slotIndex,int32_t valueBits) const40 double DebugTracePriv::interpretValueBits(int slotIndex, int32_t valueBits) const {
41 SkASSERT(slotIndex >= 0);
42 SkASSERT((size_t)slotIndex < fSlotInfo.size());
43 switch (fSlotInfo[slotIndex].numberKind) {
44 case SkSL::Type::NumberKind::kUnsigned: {
45 uint32_t uintValue;
46 static_assert(sizeof(uintValue) == sizeof(valueBits));
47 memcpy(&uintValue, &valueBits, sizeof(uintValue));
48 return uintValue;
49 }
50 case SkSL::Type::NumberKind::kFloat: {
51 float floatValue;
52 static_assert(sizeof(floatValue) == sizeof(valueBits));
53 memcpy(&floatValue, &valueBits, sizeof(floatValue));
54 return floatValue;
55 }
56 default: {
57 return valueBits;
58 }
59 }
60 }
61
slotValueToString(int slotIndex,double value) const62 std::string DebugTracePriv::slotValueToString(int slotIndex, double value) const {
63 SkASSERT(slotIndex >= 0);
64 SkASSERT((size_t)slotIndex < fSlotInfo.size());
65 switch (fSlotInfo[slotIndex].numberKind) {
66 case SkSL::Type::NumberKind::kBoolean: {
67 return value ? "true" : "false";
68 }
69 default: {
70 char buffer[32];
71 snprintf(buffer, std::size(buffer), "%.8g", value);
72 return buffer;
73 }
74 }
75 }
76
getSlotValue(int slotIndex,int32_t valueBits) const77 std::string DebugTracePriv::getSlotValue(int slotIndex, int32_t valueBits) const {
78 return this->slotValueToString(slotIndex, this->interpretValueBits(slotIndex, valueBits));
79 }
80
setTraceCoord(const SkIPoint & coord)81 void DebugTracePriv::setTraceCoord(const SkIPoint& coord) {
82 fTraceCoord = coord;
83 }
84
setSource(const std::string & source)85 void DebugTracePriv::setSource(const std::string& source) {
86 fSource.clear();
87 std::stringstream stream{source};
88 while (stream.good()) {
89 fSource.push_back({});
90 std::getline(stream, fSource.back(), '\n');
91 }
92 }
93
dump(SkWStream * o) const94 void DebugTracePriv::dump(SkWStream* o) const {
95 for (size_t index = 0; index < fSlotInfo.size(); ++index) {
96 const SlotDebugInfo& info = fSlotInfo[index];
97
98 o->writeText("$");
99 o->writeDecAsText(index);
100 o->writeText(" = ");
101 o->writeText(info.name.c_str());
102 o->writeText(" (");
103 switch (info.numberKind) {
104 case Type::NumberKind::kFloat: o->writeText("float"); break;
105 case Type::NumberKind::kSigned: o->writeText("int"); break;
106 case Type::NumberKind::kUnsigned: o->writeText("uint"); break;
107 case Type::NumberKind::kBoolean: o->writeText("bool"); break;
108 case Type::NumberKind::kNonnumeric: o->writeText("???"); break;
109 }
110 if (info.rows * info.columns > 1) {
111 o->writeDecAsText(info.columns);
112 if (info.rows != 1) {
113 o->writeText("x");
114 o->writeDecAsText(info.rows);
115 }
116 o->writeText(" : ");
117 o->writeText("slot ");
118 o->writeDecAsText(info.componentIndex + 1);
119 o->writeText("/");
120 o->writeDecAsText(info.rows * info.columns);
121 }
122 o->writeText(", L");
123 o->writeDecAsText(info.line);
124 o->writeText(")");
125 o->newline();
126 }
127
128 for (size_t index = 0; index < fFuncInfo.size(); ++index) {
129 const FunctionDebugInfo& info = fFuncInfo[index];
130
131 o->writeText("F");
132 o->writeDecAsText(index);
133 o->writeText(" = ");
134 o->writeText(info.name.c_str());
135 o->newline();
136 }
137
138 o->newline();
139
140 if (!fTraceInfo.empty()) {
141 std::string indent = "";
142 for (const SkSL::TraceInfo& traceInfo : fTraceInfo) {
143 int data0 = traceInfo.data[0];
144 int data1 = traceInfo.data[1];
145 switch (traceInfo.op) {
146 case SkSL::TraceInfo::Op::kLine:
147 o->writeText(indent.c_str());
148 o->writeText("line ");
149 o->writeDecAsText(data0);
150 break;
151
152 case SkSL::TraceInfo::Op::kVar: {
153 const SlotDebugInfo& slot = fSlotInfo[data0];
154 o->writeText(indent.c_str());
155 o->writeText(slot.name.c_str());
156 o->writeText(this->getSlotComponentSuffix(data0).c_str());
157 o->writeText(" = ");
158 o->writeText(this->getSlotValue(data0, data1).c_str());
159 break;
160 }
161 case SkSL::TraceInfo::Op::kEnter:
162 o->writeText(indent.c_str());
163 o->writeText("enter ");
164 o->writeText(fFuncInfo[data0].name.c_str());
165 indent += " ";
166 break;
167
168 case SkSL::TraceInfo::Op::kExit:
169 indent.resize(indent.size() - 2);
170 o->writeText(indent.c_str());
171 o->writeText("exit ");
172 o->writeText(fFuncInfo[data0].name.c_str());
173 break;
174
175 case SkSL::TraceInfo::Op::kScope:
176 for (int delta = data0; delta < 0; ++delta) {
177 indent.pop_back();
178 }
179 o->writeText(indent.c_str());
180 o->writeText("scope ");
181 o->writeText((data0 >= 0) ? "+" : "");
182 o->writeDecAsText(data0);
183 for (int delta = data0; delta > 0; --delta) {
184 indent.push_back(' ');
185 }
186 break;
187 }
188 o->newline();
189 }
190 }
191 }
192
193 } // namespace SkSL
194