Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkSLDebugTracePriv.cpp
Go to the documentation of this file.
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
9
10#include "include/core/SkData.h"
16#include "src/utils/SkJSON.h"
18
19#include <cstdio>
20#include <cstring>
21#include <sstream>
22#include <string>
23#include <string_view>
24
25static constexpr char kTraceVersion[] = "20220209";
26
27namespace SkSL {
28
29std::string DebugTracePriv::getSlotComponentSuffix(int slotIndex) const {
30 const SkSL::SlotDebugInfo& slot = fSlotInfo[slotIndex];
31
32 if (slot.rows > 1) {
33 return "[" + std::to_string(slot.componentIndex / slot.rows) +
34 "][" + std::to_string(slot.componentIndex % slot.rows) +
35 "]";
36 }
37 if (slot.columns > 1) {
38 switch (slot.componentIndex) {
39 case 0: return ".x";
40 case 1: return ".y";
41 case 2: return ".z";
42 case 3: return ".w";
43 default: return "[???]";
44 }
45 }
46 return {};
47}
48
49double DebugTracePriv::interpretValueBits(int slotIndex, int32_t valueBits) const {
50 SkASSERT(slotIndex >= 0);
51 SkASSERT((size_t)slotIndex < fSlotInfo.size());
52 switch (fSlotInfo[slotIndex].numberKind) {
54 uint32_t uintValue;
55 static_assert(sizeof(uintValue) == sizeof(valueBits));
56 memcpy(&uintValue, &valueBits, sizeof(uintValue));
57 return uintValue;
58 }
60 float floatValue;
61 static_assert(sizeof(floatValue) == sizeof(valueBits));
62 memcpy(&floatValue, &valueBits, sizeof(floatValue));
63 return floatValue;
64 }
65 default: {
66 return valueBits;
67 }
68 }
69}
70
71std::string DebugTracePriv::slotValueToString(int slotIndex, double value) const {
72 SkASSERT(slotIndex >= 0);
73 SkASSERT((size_t)slotIndex < fSlotInfo.size());
74 switch (fSlotInfo[slotIndex].numberKind) {
76 return value ? "true" : "false";
77 }
78 default: {
79 char buffer[32];
80 snprintf(buffer, std::size(buffer), "%.8g", value);
81 return buffer;
82 }
83 }
84}
85
86std::string DebugTracePriv::getSlotValue(int slotIndex, int32_t valueBits) const {
87 return this->slotValueToString(slotIndex, this->interpretValueBits(slotIndex, valueBits));
88}
89
91 fTraceCoord = coord;
92}
93
94void DebugTracePriv::setSource(const std::string& source) {
95 fSource.clear();
96 std::stringstream stream{source};
97 while (stream.good()) {
98 fSource.push_back({});
99 std::getline(stream, fSource.back(), '\n');
100 }
101}
102
104 for (size_t index = 0; index < fSlotInfo.size(); ++index) {
105 const SlotDebugInfo& info = fSlotInfo[index];
106
107 o->writeText("$");
108 o->writeDecAsText(index);
109 o->writeText(" = ");
110 o->writeText(info.name.c_str());
111 o->writeText(" (");
112 switch (info.numberKind) {
113 case Type::NumberKind::kFloat: o->writeText("float"); break;
114 case Type::NumberKind::kSigned: o->writeText("int"); break;
115 case Type::NumberKind::kUnsigned: o->writeText("uint"); break;
116 case Type::NumberKind::kBoolean: o->writeText("bool"); break;
117 case Type::NumberKind::kNonnumeric: o->writeText("???"); break;
118 }
119 if (info.rows * info.columns > 1) {
120 o->writeDecAsText(info.columns);
121 if (info.rows != 1) {
122 o->writeText("x");
123 o->writeDecAsText(info.rows);
124 }
125 o->writeText(" : ");
126 o->writeText("slot ");
127 o->writeDecAsText(info.componentIndex + 1);
128 o->writeText("/");
129 o->writeDecAsText(info.rows * info.columns);
130 }
131 o->writeText(", L");
132 o->writeDecAsText(info.line);
133 o->writeText(")");
134 o->newline();
135 }
136
137 for (size_t index = 0; index < fFuncInfo.size(); ++index) {
138 const FunctionDebugInfo& info = fFuncInfo[index];
139
140 o->writeText("F");
141 o->writeDecAsText(index);
142 o->writeText(" = ");
143 o->writeText(info.name.c_str());
144 o->newline();
145 }
146
147 o->newline();
148
149 if (!fTraceInfo.empty()) {
150 std::string indent = "";
151 for (const SkSL::TraceInfo& traceInfo : fTraceInfo) {
152 int data0 = traceInfo.data[0];
153 int data1 = traceInfo.data[1];
154 switch (traceInfo.op) {
155 case SkSL::TraceInfo::Op::kLine:
156 o->writeText(indent.c_str());
157 o->writeText("line ");
158 o->writeDecAsText(data0);
159 break;
160
161 case SkSL::TraceInfo::Op::kVar: {
162 const SlotDebugInfo& slot = fSlotInfo[data0];
163 o->writeText(indent.c_str());
164 o->writeText(slot.name.c_str());
165 o->writeText(this->getSlotComponentSuffix(data0).c_str());
166 o->writeText(" = ");
167 o->writeText(this->getSlotValue(data0, data1).c_str());
168 break;
169 }
170 case SkSL::TraceInfo::Op::kEnter:
171 o->writeText(indent.c_str());
172 o->writeText("enter ");
173 o->writeText(fFuncInfo[data0].name.c_str());
174 indent += " ";
175 break;
176
177 case SkSL::TraceInfo::Op::kExit:
178 indent.resize(indent.size() - 2);
179 o->writeText(indent.c_str());
180 o->writeText("exit ");
181 o->writeText(fFuncInfo[data0].name.c_str());
182 break;
183
184 case SkSL::TraceInfo::Op::kScope:
185 for (int delta = data0; delta < 0; ++delta) {
186 indent.pop_back();
187 }
188 o->writeText(indent.c_str());
189 o->writeText("scope ");
190 o->writeText((data0 >= 0) ? "+" : "");
191 o->writeDecAsText(data0);
192 for (int delta = data0; delta > 0; --delta) {
193 indent.push_back(' ');
194 }
195 break;
196 }
197 o->newline();
198 }
199 }
200}
201
203 SkJSONWriter json(w);
204
205 json.beginObject(); // root
206 json.appendNString("version", kTraceVersion);
207 json.beginArray("source");
208
209 for (const std::string& line : fSource) {
210 json.appendString(line);
211 }
212
213 json.endArray(); // code
214 json.beginArray("slots");
215
216 for (size_t index = 0; index < fSlotInfo.size(); ++index) {
217 const SlotDebugInfo& info = fSlotInfo[index];
218
219 json.beginObject();
220 json.appendString("name", info.name.data(), info.name.size());
221 json.appendS32("columns", info.columns);
222 json.appendS32("rows", info.rows);
223 json.appendS32("index", info.componentIndex);
224 if (info.groupIndex != info.componentIndex) {
225 json.appendS32("groupIdx", info.groupIndex);
226 }
227 json.appendS32("kind", (int)info.numberKind);
228 json.appendS32("line", info.line);
229 if (info.fnReturnValue >= 0) {
230 json.appendS32("retval", info.fnReturnValue);
231 }
232 json.endObject();
233 }
234
235 json.endArray(); // slots
236 json.beginArray("functions");
237
238 for (size_t index = 0; index < fFuncInfo.size(); ++index) {
239 const FunctionDebugInfo& info = fFuncInfo[index];
240
241 json.beginObject();
242 json.appendString("name", info.name);
243 json.endObject();
244 }
245
246 json.endArray(); // functions
247 json.beginArray("trace");
248
249 for (size_t index = 0; index < fTraceInfo.size(); ++index) {
250 const TraceInfo& trace = fTraceInfo[index];
251 json.beginArray();
252 json.appendS32((int)trace.op);
253
254 // Skip trailing zeros in the data (since most ops only use one value).
255 int lastDataIdx = std::size(trace.data) - 1;
256 while (lastDataIdx >= 0 && !trace.data[lastDataIdx]) {
257 --lastDataIdx;
258 }
259 for (int dataIdx = 0; dataIdx <= lastDataIdx; ++dataIdx) {
260 json.appendS32(trace.data[dataIdx]);
261 }
262 json.endArray();
263 }
264
265 json.endArray(); // trace
266 json.endObject(); // root
267 json.flush();
268}
269
272 skjson::DOM json(reinterpret_cast<const char*>(data->bytes()), data->size());
273 const skjson::ObjectValue* root = json.root();
274 if (!root) {
275 return false;
276 }
277
278 const skjson::StringValue* version = (*root)["version"];
279 if (!version || version->str() != kTraceVersion) {
280 return false;
281 }
282
283 const skjson::ArrayValue* source = (*root)["source"];
284 if (!source) {
285 return false;
286 }
287
288 fSource.clear();
289 for (const skjson::StringValue* line : *source) {
290 if (!line) {
291 return false;
292 }
293 fSource.push_back(line->begin());
294 }
295
296 const skjson::ArrayValue* slots = (*root)["slots"];
297 if (!slots) {
298 return false;
299 }
300
301 fSlotInfo.clear();
302 for (const skjson::ObjectValue* element : *slots) {
303 if (!element) {
304 return false;
305 }
306
307 // Grow the slot array to hold this element.
308 fSlotInfo.push_back({});
309 SlotDebugInfo& info = fSlotInfo.back();
310
311 // Populate the SlotInfo with our JSON data.
312 const skjson::StringValue* name = (*element)["name"];
313 const skjson::NumberValue* columns = (*element)["columns"];
314 const skjson::NumberValue* rows = (*element)["rows"];
315 const skjson::NumberValue* index = (*element)["index"];
316 const skjson::NumberValue* groupIdx = (*element)["groupIdx"];
317 const skjson::NumberValue* kind = (*element)["kind"];
318 const skjson::NumberValue* line = (*element)["line"];
319 const skjson::NumberValue* retval = (*element)["retval"];
320 if (!name || !columns || !rows || !index || !kind || !line) {
321 return false;
322 }
323
324 info.name = name->begin();
325 info.columns = **columns;
326 info.rows = **rows;
327 info.componentIndex = **index;
328 info.groupIndex = groupIdx ? **groupIdx : info.componentIndex;
329 info.numberKind = (SkSL::Type::NumberKind)(int)**kind;
330 info.line = **line;
331 info.fnReturnValue = retval ? **retval : -1;
332 }
333
334 const skjson::ArrayValue* functions = (*root)["functions"];
335 if (!functions) {
336 return false;
337 }
338
339 fFuncInfo.clear();
340 for (const skjson::ObjectValue* element : *functions) {
341 if (!element) {
342 return false;
343 }
344
345 // Grow the function array to hold this element.
346 fFuncInfo.push_back({});
348
349 // Populate the FunctionInfo with our JSON data.
350 const skjson::StringValue* name = (*element)["name"];
351 if (!name) {
352 return false;
353 }
354
355 info.name = name->begin();
356 }
357
358 const skjson::ArrayValue* trace = (*root)["trace"];
359 if (!trace) {
360 return false;
361 }
362
363 fTraceInfo.clear();
364 fTraceInfo.reserve(trace->size());
365 for (const skjson::ArrayValue* element : *trace) {
366 fTraceInfo.push_back(TraceInfo{});
367 TraceInfo& info = fTraceInfo.back();
368
369 if (!element || element->size() < 1 || element->size() > (1 + std::size(info.data))) {
370 return false;
371 }
372 const skjson::NumberValue* opVal = (*element)[0];
373 if (!opVal) {
374 return false;
375 }
376 info.op = (TraceInfo::Op)(int)**opVal;
377 for (size_t elemIdx = 1; elemIdx < element->size(); ++elemIdx) {
378 const skjson::NumberValue* dataVal = (*element)[elemIdx];
379 if (!dataVal) {
380 return false;
381 }
382 info.data[elemIdx - 1] = **dataVal;
383 }
384 }
385
386 return true;
387}
388
389} // namespace SkSL
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
#define SkASSERT(cond)
Definition SkAssert.h:116
static constexpr char kTraceVersion[]
sk_sp< SkData > SkCopyStreamToData(SkStream *stream)
Definition SkStream.cpp:937
void appendS32(int32_t value)
void appendNString(char const (&value)[N])
void beginArray(const char *name=nullptr, bool multiline=true)
void beginObject(const char *name=nullptr, bool multiline=true)
void appendString(const char *value, size_t size)
void writeTrace(SkWStream *w) const override
std::string getSlotValue(int slotIndex, int32_t value) const
bool readTrace(SkStream *r)
std::vector< FunctionDebugInfo > fFuncInfo
void setSource(const std::string &source)
std::vector< TraceInfo > fTraceInfo
void setTraceCoord(const SkIPoint &coord)
std::vector< std::string > fSource
std::vector< SlotDebugInfo > fSlotInfo
double interpretValueBits(int slotIndex, int32_t valueBits) const
void dump(SkWStream *o) const override
std::string slotValueToString(int slotIndex, double value) const
std::string getSlotComponentSuffix(int slotIndex) const
bool writeDecAsText(int32_t)
Definition SkStream.cpp:81
bool writeText(const char text[])
Definition SkStream.h:247
bool newline()
Definition SkStream.h:252
const Value & root() const
Definition SkJSON.h:362
const char * begin() const
Definition SkJSON.h:315
size_t size() const
Definition SkJSON.h:262
SkBitmap source
Definition examples.cpp:28
static const uint8_t buffer[]
uint8_t value
const char * name
Definition fuchsia.cc:50
SkScalar w