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