• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Amber Authors.
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 "src/vkscript/command_parser.h"
16 
17 #include <algorithm>
18 #include <cassert>
19 #include <cctype>
20 #include <limits>
21 #include <string>
22 #include <utility>
23 
24 #include "src/command_data.h"
25 #include "src/make_unique.h"
26 #include "src/tokenizer.h"
27 #include "src/type_parser.h"
28 #include "src/vkscript/datum_type_parser.h"
29 
30 namespace amber {
31 namespace vkscript {
32 namespace {
33 
ShaderNameToType(const std::string & name)34 ShaderType ShaderNameToType(const std::string& name) {
35   if (name == "fragment")
36     return kShaderTypeFragment;
37   if (name == "compute")
38     return kShaderTypeCompute;
39   if (name == "geometry")
40     return kShaderTypeGeometry;
41   if (name == "tessellation evaluation")
42     return kShaderTypeTessellationEvaluation;
43   if (name == "tessellation control")
44     return kShaderTypeTessellationControl;
45 
46   return kShaderTypeVertex;
47 }
48 
49 }  // namespace
50 
CommandParser(Script * script,Pipeline * pipeline,size_t current_line,const std::string & data)51 CommandParser::CommandParser(Script* script,
52                              Pipeline* pipeline,
53                              size_t current_line,
54                              const std::string& data)
55     : script_(script),
56       pipeline_(pipeline),
57       tokenizer_(MakeUnique<Tokenizer>(data)) {
58   tokenizer_->SetCurrentLine(current_line);
59 }
60 
61 CommandParser::~CommandParser() = default;
62 
make_error(const std::string & err)63 std::string CommandParser::make_error(const std::string& err) {
64   return std::to_string(tokenizer_->GetCurrentLine()) + ": " + err;
65 }
66 
ParseBoolean(const std::string & str,bool * result)67 Result CommandParser::ParseBoolean(const std::string& str, bool* result) {
68   assert(result);
69 
70   std::string tmp;
71   tmp.resize(str.size());
72   std::transform(str.begin(), str.end(), tmp.begin(),
73                  [](unsigned char c) { return std::tolower(c); });
74 
75   if (tmp == "true") {
76     *result = true;
77     return {};
78   }
79   if (tmp == "false") {
80     *result = false;
81     return {};
82   }
83   return Result("Invalid value passed as a boolean string: " + str);
84 }
85 
Parse()86 Result CommandParser::Parse() {
87   for (auto token = tokenizer_->NextToken(); !token->IsEOS();
88        token = tokenizer_->NextToken()) {
89     if (token->IsEOL())
90       continue;
91 
92     if (!token->IsString()) {
93       return Result(make_error(
94           "Command not recognized. Received something other then a string: " +
95           token->ToOriginalString()));
96     }
97 
98     std::string cmd_name = token->AsString();
99     Result r;
100     if (cmd_name == "draw") {
101       token = tokenizer_->NextToken();
102       if (!token->IsString())
103         return Result(make_error("Invalid draw command in test: " +
104                                  token->ToOriginalString()));
105 
106       cmd_name = token->AsString();
107       if (cmd_name == "rect")
108         r = ProcessDrawRect();
109       else if (cmd_name == "arrays")
110         r = ProcessDrawArrays();
111       else
112         r = Result("Unknown draw command: " + cmd_name);
113 
114     } else if (cmd_name == "clear") {
115       r = ProcessClear();
116     } else if (cmd_name == "ssbo") {
117       r = ProcessSSBO();
118     } else if (cmd_name == "uniform") {
119       r = ProcessUniform();
120     } else if (cmd_name == "patch") {
121       r = ProcessPatch();
122     } else if (cmd_name == "probe") {
123       r = ProcessProbe(false);
124     } else if (cmd_name == "tolerance") {
125       r = ProcessTolerance();
126     } else if (cmd_name == "relative") {
127       token = tokenizer_->NextToken();
128       if (!token->IsString() || token->AsString() != "probe")
129         return Result(make_error("relative must be used with probe: " +
130                                  token->ToOriginalString()));
131 
132       r = ProcessProbe(true);
133     } else if (cmd_name == "compute") {
134       r = ProcessCompute();
135     } else if (cmd_name == "vertex" || cmd_name == "fragment" ||
136                cmd_name == "geometry" || cmd_name == "tessellation") {
137       std::string shader_name = cmd_name;
138       if (cmd_name == "tessellation") {
139         token = tokenizer_->NextToken();
140         if (!token->IsString() || (token->AsString() != "control" &&
141                                    token->AsString() != "evaluation")) {
142           return Result(
143               make_error("Tessellation entrypoint must have "
144                          "<evaluation|control> in name: " +
145                          token->ToOriginalString()));
146         }
147         shader_name += " " + token->AsString();
148       }
149 
150       token = tokenizer_->NextToken();
151       if (!token->IsString() || token->AsString() != "entrypoint")
152         return Result(make_error("Unknown command: " + shader_name));
153 
154       r = ProcessEntryPoint(shader_name);
155 
156       // Pipeline Commands
157     } else if (cmd_name == "primitiveRestartEnable") {
158       r = ProcessPrimitiveRestartEnable();
159     } else if (cmd_name == "depthClampEnable") {
160       r = ProcessDepthClampEnable();
161     } else if (cmd_name == "rasterizerDiscardEnable") {
162       r = ProcessRasterizerDiscardEnable();
163     } else if (cmd_name == "depthBiasEnable") {
164       r = ProcessDepthBiasEnable();
165     } else if (cmd_name == "logicOpEnable") {
166       r = ProcessLogicOpEnable();
167     } else if (cmd_name == "blendEnable") {
168       r = ProcessBlendEnable();
169     } else if (cmd_name == "depthTestEnable") {
170       r = ProcessDepthTestEnable();
171     } else if (cmd_name == "depthWriteEnable") {
172       r = ProcessDepthWriteEnable();
173     } else if (cmd_name == "depthBoundsTestEnable") {
174       r = ProcessDepthBoundsTestEnable();
175     } else if (cmd_name == "stencilTestEnable") {
176       r = ProcessStencilTestEnable();
177     } else if (cmd_name == "topology") {
178       r = ProcessTopology();
179     } else if (cmd_name == "polygonMode") {
180       r = ProcessPolygonMode();
181     } else if (cmd_name == "logicOp") {
182       r = ProcessLogicOp();
183     } else if (cmd_name == "frontFace") {
184       r = ProcessFrontFace();
185     } else if (cmd_name == "cullMode") {
186       r = ProcessCullMode();
187     } else if (cmd_name == "depthBiasConstantFactor") {
188       r = ProcessDepthBiasConstantFactor();
189     } else if (cmd_name == "depthBiasClamp") {
190       r = ProcessDepthBiasClamp();
191     } else if (cmd_name == "depthBiasSlopeFactor") {
192       r = ProcessDepthBiasSlopeFactor();
193     } else if (cmd_name == "lineWidth") {
194       r = ProcessLineWidth();
195     } else if (cmd_name == "minDepthBounds") {
196       r = ProcessMinDepthBounds();
197     } else if (cmd_name == "maxDepthBounds") {
198       r = ProcessMaxDepthBounds();
199     } else if (cmd_name == "srcColorBlendFactor") {
200       r = ProcessSrcColorBlendFactor();
201     } else if (cmd_name == "dstColorBlendFactor") {
202       r = ProcessDstColorBlendFactor();
203     } else if (cmd_name == "srcAlphaBlendFactor") {
204       r = ProcessSrcAlphaBlendFactor();
205     } else if (cmd_name == "dstAlphaBlendFactor") {
206       r = ProcessDstAlphaBlendFactor();
207     } else if (cmd_name == "colorBlendOp") {
208       r = ProcessColorBlendOp();
209     } else if (cmd_name == "alphaBlendOp") {
210       r = ProcessAlphaBlendOp();
211     } else if (cmd_name == "depthCompareOp") {
212       r = ProcessDepthCompareOp();
213     } else if (cmd_name == "front.compareOp") {
214       r = ProcessFrontCompareOp();
215     } else if (cmd_name == "back.compareOp") {
216       r = ProcessBackCompareOp();
217     } else if (cmd_name == "front.failOp") {
218       r = ProcessFrontFailOp();
219     } else if (cmd_name == "front.passOp") {
220       r = ProcessFrontPassOp();
221     } else if (cmd_name == "front.depthFailOp") {
222       r = ProcessFrontDepthFailOp();
223     } else if (cmd_name == "back.failOp") {
224       r = ProcessBackFailOp();
225     } else if (cmd_name == "back.passOp") {
226       r = ProcessBackPassOp();
227     } else if (cmd_name == "back.depthFailOp") {
228       r = ProcessBackDepthFailOp();
229     } else if (cmd_name == "front.compareMask") {
230       r = ProcessFrontCompareMask();
231     } else if (cmd_name == "front.writeMask") {
232       r = ProcessFrontWriteMask();
233     } else if (cmd_name == "back.compareMask") {
234       r = ProcessBackCompareMask();
235     } else if (cmd_name == "back.writeMask") {
236       r = ProcessBackWriteMask();
237     } else if (cmd_name == "front.reference") {
238       r = ProcessFrontReference();
239     } else if (cmd_name == "back.reference") {
240       r = ProcessBackReference();
241     } else if (cmd_name == "colorWriteMask") {
242       r = ProcessColorWriteMask();
243     } else {
244       r = Result("Unknown command: " + cmd_name);
245     }
246 
247     if (!r.IsSuccess())
248       return Result(make_error(r.Error()));
249   }
250 
251   return {};
252 }
253 
ProcessDrawRect()254 Result CommandParser::ProcessDrawRect() {
255   auto cmd = MakeUnique<DrawRectCommand>(pipeline_, pipeline_data_);
256   cmd->SetLine(tokenizer_->GetCurrentLine());
257 
258   if (pipeline_->GetVertexBuffers().size() > 1) {
259     return Result(
260         "draw rect command is not supported in a pipeline with more than one "
261         "vertex buffer attached");
262   }
263 
264   auto token = tokenizer_->NextToken();
265   while (token->IsString()) {
266     std::string str = token->AsString();
267     if (str != "ortho" && str != "patch")
268       return Result("Unknown parameter to draw rect: " + str);
269 
270     if (str == "ortho") {
271       cmd->EnableOrtho();
272     } else {
273       cmd->EnablePatch();
274     }
275     token = tokenizer_->NextToken();
276   }
277 
278   Result r = token->ConvertToDouble();
279   if (!r.IsSuccess())
280     return r;
281   cmd->SetX(token->AsFloat());
282 
283   token = tokenizer_->NextToken();
284   r = token->ConvertToDouble();
285   if (!r.IsSuccess())
286     return r;
287   cmd->SetY(token->AsFloat());
288 
289   token = tokenizer_->NextToken();
290   r = token->ConvertToDouble();
291   if (!r.IsSuccess())
292     return r;
293   cmd->SetWidth(token->AsFloat());
294 
295   token = tokenizer_->NextToken();
296   r = token->ConvertToDouble();
297   if (!r.IsSuccess())
298     return r;
299   cmd->SetHeight(token->AsFloat());
300 
301   token = tokenizer_->NextToken();
302   if (!token->IsEOS() && !token->IsEOL())
303     return Result("Extra parameter to draw rect command: " +
304                   token->ToOriginalString());
305 
306   commands_.push_back(std::move(cmd));
307   return {};
308 }
309 
ProcessDrawArrays()310 Result CommandParser::ProcessDrawArrays() {
311   auto cmd = MakeUnique<DrawArraysCommand>(pipeline_, pipeline_data_);
312   cmd->SetLine(tokenizer_->GetCurrentLine());
313 
314   auto token = tokenizer_->NextToken();
315   while (token->IsString()) {
316     std::string str = token->AsString();
317     if (str != "indexed" && str != "instanced") {
318       Topology topo = NameToTopology(token->AsString());
319       if (topo != Topology::kUnknown) {
320         cmd->SetTopology(topo);
321 
322         // Advance token here so we're consistent with the non-topology case.
323         token = tokenizer_->NextToken();
324         break;
325       }
326       return Result("Unknown parameter to draw arrays: " + str);
327     }
328 
329     if (str == "indexed") {
330       cmd->EnableIndexed();
331     } else {
332       cmd->EnableInstanced();
333     }
334     token = tokenizer_->NextToken();
335   }
336 
337   if (cmd->GetTopology() == Topology::kUnknown)
338     return Result("Missing draw arrays topology");
339 
340   if (!token->IsInteger())
341     return Result("Missing integer first vertex value for draw arrays: " +
342                   token->ToOriginalString());
343   cmd->SetFirstVertexIndex(token->AsUint32());
344 
345   token = tokenizer_->NextToken();
346   if (!token->IsInteger())
347     return Result("Missing integer vertex count value for draw arrays: " +
348                   token->ToOriginalString());
349   cmd->SetVertexCount(token->AsUint32());
350 
351   token = tokenizer_->NextToken();
352   if (cmd->IsInstanced()) {
353     if (!token->IsEOL() && !token->IsEOS()) {
354       if (!token->IsInteger())
355         return Result("Invalid instance count for draw arrays: " +
356                       token->ToOriginalString());
357 
358       cmd->SetInstanceCount(token->AsUint32());
359     }
360     token = tokenizer_->NextToken();
361   }
362 
363   if (!token->IsEOL() && !token->IsEOS())
364     return Result("Extra parameter to draw arrays command: " +
365                   token->ToOriginalString());
366 
367   commands_.push_back(std::move(cmd));
368   return {};
369 }
370 
ProcessCompute()371 Result CommandParser::ProcessCompute() {
372   auto cmd = MakeUnique<ComputeCommand>(pipeline_);
373   cmd->SetLine(tokenizer_->GetCurrentLine());
374 
375   auto token = tokenizer_->NextToken();
376 
377   // Compute can start a compute line or an entryp oint line ...
378   if (token->IsString() && token->AsString() == "entrypoint")
379     return ProcessEntryPoint("compute");
380 
381   if (!token->IsInteger())
382     return Result("Missing integer value for compute X entry: " +
383                   token->ToOriginalString());
384   cmd->SetX(token->AsUint32());
385 
386   token = tokenizer_->NextToken();
387   if (!token->IsInteger())
388     return Result("Missing integer value for compute Y entry: " +
389                   token->ToOriginalString());
390   cmd->SetY(token->AsUint32());
391 
392   token = tokenizer_->NextToken();
393   if (!token->IsInteger())
394     return Result("Missing integer value for compute Z entry: " +
395                   token->ToOriginalString());
396   cmd->SetZ(token->AsUint32());
397 
398   token = tokenizer_->NextToken();
399   if (!token->IsEOS() && !token->IsEOL())
400     return Result("Extra parameter to compute command: " +
401                   token->ToOriginalString());
402 
403   commands_.push_back(std::move(cmd));
404   return {};
405 }
406 
ProcessClear()407 Result CommandParser::ProcessClear() {
408   std::unique_ptr<Command> cmd;
409 
410   auto token = tokenizer_->NextToken();
411   std::string cmd_suffix = "";
412   if (token->IsString()) {
413     std::string str = token->AsString();
414     cmd_suffix = str + " ";
415     if (str == "depth") {
416       cmd = MakeUnique<ClearDepthCommand>(pipeline_);
417       cmd->SetLine(tokenizer_->GetCurrentLine());
418 
419       token = tokenizer_->NextToken();
420       Result r = token->ConvertToDouble();
421       if (!r.IsSuccess())
422         return r;
423 
424       cmd->AsClearDepth()->SetValue(token->AsFloat());
425     } else if (str == "stencil") {
426       cmd = MakeUnique<ClearStencilCommand>(pipeline_);
427       cmd->SetLine(tokenizer_->GetCurrentLine());
428 
429       token = tokenizer_->NextToken();
430       if (token->IsEOL() || token->IsEOS())
431         return Result("Missing stencil value for clear stencil command: " +
432                       token->ToOriginalString());
433       if (!token->IsInteger())
434         return Result("Invalid stencil value for clear stencil command: " +
435                       token->ToOriginalString());
436 
437       cmd->AsClearStencil()->SetValue(token->AsUint32());
438     } else if (str == "color") {
439       cmd = MakeUnique<ClearColorCommand>(pipeline_);
440       cmd->SetLine(tokenizer_->GetCurrentLine());
441 
442       token = tokenizer_->NextToken();
443       Result r = token->ConvertToDouble();
444       if (!r.IsSuccess())
445         return r;
446       cmd->AsClearColor()->SetR(token->AsFloat());
447 
448       token = tokenizer_->NextToken();
449       r = token->ConvertToDouble();
450       if (!r.IsSuccess())
451         return r;
452       cmd->AsClearColor()->SetG(token->AsFloat());
453 
454       token = tokenizer_->NextToken();
455       r = token->ConvertToDouble();
456       if (!r.IsSuccess())
457         return r;
458       cmd->AsClearColor()->SetB(token->AsFloat());
459 
460       token = tokenizer_->NextToken();
461       r = token->ConvertToDouble();
462       if (!r.IsSuccess())
463         return r;
464       cmd->AsClearColor()->SetA(token->AsFloat());
465     } else {
466       return Result("Extra parameter to clear command: " +
467                     token->ToOriginalString());
468     }
469 
470     token = tokenizer_->NextToken();
471   } else {
472     cmd = MakeUnique<ClearCommand>(pipeline_);
473     cmd->SetLine(tokenizer_->GetCurrentLine());
474   }
475   if (!token->IsEOS() && !token->IsEOL())
476     return Result("Extra parameter to clear " + cmd_suffix +
477                   "command: " + token->ToOriginalString());
478 
479   commands_.push_back(std::move(cmd));
480   return {};
481 }
482 
ParseValues(const std::string & name,Format * fmt,std::vector<Value> * values)483 Result CommandParser::ParseValues(const std::string& name,
484                                   Format* fmt,
485                                   std::vector<Value>* values) {
486   assert(values);
487 
488   uint32_t row_index = 0;
489   auto token = tokenizer_->NextToken();
490   size_t seen = 0;
491   while (!token->IsEOL() && !token->IsEOS()) {
492     Value v;
493 
494     if ((fmt->IsFloat32() || fmt->IsFloat64())) {
495       if (!token->IsInteger() && !token->IsDouble()) {
496         return Result(std::string("Invalid value provided to ") + name +
497                       " command: " + token->ToOriginalString());
498       }
499 
500       Result r = token->ConvertToDouble();
501       if (!r.IsSuccess())
502         return r;
503 
504       v.SetDoubleValue(token->AsDouble());
505     } else {
506       if (!token->IsInteger()) {
507         return Result(std::string("Invalid value provided to ") + name +
508                       " command: " + token->ToOriginalString());
509       }
510 
511       v.SetIntValue(token->AsUint64());
512     }
513 
514     values->push_back(v);
515     token = tokenizer_->NextToken();
516 
517     ++row_index;
518     ++seen;
519   }
520 
521   // This could overflow, but I don't really expect us to get command files
522   // that big ....
523   size_t num_per_row = fmt->GetType()->RowCount();
524   if (seen == 0 || (seen % num_per_row) != 0) {
525     return Result(std::string("Incorrect number of values provided to ") +
526                   name + " command");
527   }
528 
529   return {};
530 }
531 
ProcessSSBO()532 Result CommandParser::ProcessSSBO() {
533   auto cmd =
534       MakeUnique<BufferCommand>(BufferCommand::BufferType::kSSBO, pipeline_);
535   cmd->SetLine(tokenizer_->GetCurrentLine());
536 
537   auto token = tokenizer_->NextToken();
538   if (token->IsEOL() || token->IsEOS())
539     return Result("Missing binding and size values for ssbo command");
540   if (!token->IsInteger())
541     return Result("Invalid binding value for ssbo command");
542 
543   uint32_t val = token->AsUint32();
544 
545   token = tokenizer_->NextToken();
546   if (token->IsString() && token->AsString() != "subdata") {
547     auto& str = token->AsString();
548     if (str.size() >= 2 && str[0] == ':') {
549       cmd->SetDescriptorSet(val);
550 
551       auto substr = str.substr(1, str.size());
552       uint64_t binding_val = strtoul(substr.c_str(), nullptr, 10);
553       if (binding_val > std::numeric_limits<uint32_t>::max())
554         return Result("binding value too large in ssbo command");
555 
556       cmd->SetBinding(static_cast<uint32_t>(binding_val));
557     } else {
558       return Result("Invalid value for ssbo command: " +
559                     token->ToOriginalString());
560     }
561 
562     token = tokenizer_->NextToken();
563   } else {
564     cmd->SetBinding(val);
565   }
566 
567   {
568     // Generate an internal buffer for this binding if needed.
569     auto set = cmd->GetDescriptorSet();
570     auto binding = cmd->GetBinding();
571 
572     auto* buffer = pipeline_->GetBufferForBinding(set, binding);
573     if (!buffer) {
574       auto b = MakeUnique<Buffer>(BufferType::kStorage);
575       b->SetName("AutoBuf-" + std::to_string(script_->GetBuffers().size()));
576       buffer = b.get();
577       script_->AddBuffer(std::move(b));
578       pipeline_->AddBuffer(buffer, set, binding);
579     }
580     cmd->SetBuffer(buffer);
581   }
582 
583   if (token->IsString() && token->AsString() == "subdata") {
584     cmd->SetIsSubdata();
585 
586     token = tokenizer_->NextToken();
587     if (!token->IsString())
588       return Result("Invalid type for ssbo command: " +
589                     token->ToOriginalString());
590 
591     DatumTypeParser tp;
592     auto type = tp.Parse(token->AsString());
593     if (!type)
594       return Result("Invalid type provided: " + token->AsString());
595 
596     auto fmt = MakeUnique<Format>(type.get());
597     auto* buf = cmd->GetBuffer();
598     if (buf->FormatIsDefault() || !buf->GetFormat()) {
599       buf->SetFormat(fmt.get());
600       script_->RegisterFormat(std::move(fmt));
601       script_->RegisterType(std::move(type));
602     } else if (!buf->GetFormat()->Equal(fmt.get())) {
603       return Result("probe ssbo format does not match buffer format");
604     }
605 
606     token = tokenizer_->NextToken();
607     if (!token->IsInteger()) {
608       return Result("Invalid offset for ssbo command: " +
609                     token->ToOriginalString());
610     }
611     if (token->AsInt32() < 0) {
612       return Result("offset for SSBO must be positive, got: " +
613                     std::to_string(token->AsInt32()));
614     }
615     if ((token->AsUint32() % buf->GetFormat()->SizeInBytes()) != 0) {
616       return Result(
617           "offset for SSBO must be a multiple of the data size expected " +
618           std::to_string(buf->GetFormat()->SizeInBytes()));
619     }
620 
621     cmd->SetOffset(token->AsUint32());
622 
623     std::vector<Value> values;
624     Result r = ParseValues("ssbo", buf->GetFormat(), &values);
625     if (!r.IsSuccess())
626       return r;
627 
628     buf->RecalculateMaxSizeInBytes(values, cmd->GetOffset());
629 
630     cmd->SetValues(std::move(values));
631 
632   } else {
633     if (token->IsEOL() || token->IsEOS())
634       return Result("Missing size value for ssbo command: " +
635                     token->ToOriginalString());
636     if (!token->IsInteger())
637       return Result("Invalid size value for ssbo command: " +
638                     token->ToOriginalString());
639 
640     // Resize the buffer so we'll correctly create the descriptor sets.
641     auto* buf = cmd->GetBuffer();
642     buf->SetElementCount(token->AsUint32());
643 
644     // Set a default format into the buffer if needed.
645     if (!buf->GetFormat()) {
646       TypeParser parser;
647       auto type = parser.Parse("R8_SINT");
648       auto fmt = MakeUnique<Format>(type.get());
649       buf->SetFormat(fmt.get());
650       script_->RegisterFormat(std::move(fmt));
651       script_->RegisterType(std::move(type));
652 
653       // This has to come after the SetFormat() call because SetFormat() resets
654       // the value back to false.
655       buf->SetFormatIsDefault(true);
656     }
657 
658     token = tokenizer_->NextToken();
659     if (!token->IsEOS() && !token->IsEOL())
660       return Result("Extra parameter for ssbo command: " +
661                     token->ToOriginalString());
662   }
663 
664   commands_.push_back(std::move(cmd));
665   return {};
666 }
667 
ProcessUniform()668 Result CommandParser::ProcessUniform() {
669   auto token = tokenizer_->NextToken();
670   if (token->IsEOL() || token->IsEOS())
671     return Result("Missing binding and size values for uniform command: " +
672                   token->ToOriginalString());
673   if (!token->IsString())
674     return Result("Invalid type value for uniform command: " +
675                   token->ToOriginalString());
676 
677   std::unique_ptr<BufferCommand> cmd;
678   bool is_ubo = false;
679   if (token->AsString() == "ubo") {
680     cmd = MakeUnique<BufferCommand>(BufferCommand::BufferType::kUniform,
681                                     pipeline_);
682     cmd->SetLine(tokenizer_->GetCurrentLine());
683 
684     token = tokenizer_->NextToken();
685     if (!token->IsInteger()) {
686       return Result("Invalid binding value for uniform ubo command: " +
687                     token->ToOriginalString());
688     }
689 
690     uint32_t val = token->AsUint32();
691 
692     token = tokenizer_->NextToken();
693     if (!token->IsString()) {
694       return Result("Invalid type value for uniform ubo command: " +
695                     token->ToOriginalString());
696     }
697 
698     auto& str = token->AsString();
699     if (str.size() >= 2 && str[0] == ':') {
700       cmd->SetDescriptorSet(val);
701 
702       auto substr = str.substr(1, str.size());
703       uint64_t binding_val = strtoul(substr.c_str(), nullptr, 10);
704       if (binding_val > std::numeric_limits<uint32_t>::max())
705         return Result("binding value too large in uniform ubo command: " +
706                       token->ToOriginalString());
707 
708       cmd->SetBinding(static_cast<uint32_t>(binding_val));
709 
710       token = tokenizer_->NextToken();
711       if (!token->IsString()) {
712         return Result("Invalid type value for uniform ubo command: " +
713                       token->ToOriginalString());
714       }
715     } else {
716       cmd->SetBinding(val);
717     }
718     is_ubo = true;
719 
720     auto set = cmd->GetDescriptorSet();
721     auto binding = cmd->GetBinding();
722 
723     auto* buffer = pipeline_->GetBufferForBinding(set, binding);
724     if (!buffer) {
725       auto b = MakeUnique<Buffer>(BufferType::kUniform);
726       b->SetName("AutoBuf-" + std::to_string(script_->GetBuffers().size()));
727       buffer = b.get();
728       script_->AddBuffer(std::move(b));
729       pipeline_->AddBuffer(buffer, set, binding);
730     }
731     cmd->SetBuffer(buffer);
732 
733   } else {
734     cmd = MakeUnique<BufferCommand>(BufferCommand::BufferType::kPushConstant,
735                                     pipeline_);
736     cmd->SetLine(tokenizer_->GetCurrentLine());
737 
738     // Push constants don't have descriptor set and binding values. So, we do
739     // not want to try to lookup the buffer or we'll accidentally get whatever
740     // is bound at 0:0.
741     auto b = MakeUnique<Buffer>(BufferType::kUniform);
742     b->SetName("AutoBuf-" + std::to_string(script_->GetBuffers().size()));
743     cmd->SetBuffer(b.get());
744     script_->AddBuffer(std::move(b));
745   }
746 
747   DatumTypeParser tp;
748   auto type = tp.Parse(token->AsString());
749   if (!type)
750     return Result("Invalid type provided: " + token->AsString());
751 
752   auto fmt = MakeUnique<Format>(type.get());
753 
754   // uniform is always std140.
755   if (is_ubo)
756     fmt->SetLayout(Format::Layout::kStd140);
757 
758   auto* buf = cmd->GetBuffer();
759   if (buf->FormatIsDefault() || !buf->GetFormat()) {
760     buf->SetFormat(fmt.get());
761     script_->RegisterFormat(std::move(fmt));
762     script_->RegisterType(std::move(type));
763   } else if (!buf->GetFormat()->Equal(fmt.get())) {
764     return Result("probe ssbo format does not match buffer format");
765   }
766 
767   token = tokenizer_->NextToken();
768   if (!token->IsInteger()) {
769     return Result("Invalid offset value for uniform command: " +
770                   token->ToOriginalString());
771   }
772   if (token->AsInt32() < 0) {
773     return Result("offset for uniform must be positive, got: " +
774                   std::to_string(token->AsInt32()));
775   }
776 
777   auto buf_size = static_cast<int32_t>(buf->GetFormat()->SizeInBytes());
778   if (token->AsInt32() % buf_size != 0)
779     return Result("offset for uniform must be multiple of data size");
780 
781   cmd->SetOffset(token->AsUint32());
782 
783   std::vector<Value> values;
784   Result r = ParseValues("uniform", buf->GetFormat(), &values);
785   if (!r.IsSuccess())
786     return r;
787 
788   buf->RecalculateMaxSizeInBytes(values, cmd->GetOffset());
789 
790   if (cmd->IsPushConstant())
791     buf->SetData(values);
792   else
793     cmd->SetValues(std::move(values));
794 
795   commands_.push_back(std::move(cmd));
796   return {};
797 }
798 
ProcessTolerance()799 Result CommandParser::ProcessTolerance() {
800   current_tolerances_.clear();
801 
802   auto token = tokenizer_->NextToken();
803   size_t found_tokens = 0;
804   while (!token->IsEOL() && !token->IsEOS() && found_tokens < 4) {
805     if (token->IsString() && token->AsString() == ",") {
806       token = tokenizer_->NextToken();
807       continue;
808     }
809 
810     if (token->IsInteger() || token->IsDouble()) {
811       Result r = token->ConvertToDouble();
812       if (!r.IsSuccess())
813         return r;
814       double value = token->AsDouble();
815 
816       token = tokenizer_->NextToken();
817       if (token->IsString() && token->AsString() != ",") {
818         if (token->AsString() != "%")
819           return Result("Invalid value for tolerance command: " +
820                         token->ToOriginalString());
821 
822         current_tolerances_.push_back(Probe::Tolerance{true, value});
823         token = tokenizer_->NextToken();
824       } else {
825         current_tolerances_.push_back(Probe::Tolerance{false, value});
826       }
827     } else {
828       return Result("Invalid value for tolerance command: " +
829                     token->ToOriginalString());
830     }
831 
832     ++found_tokens;
833   }
834   if (found_tokens == 0)
835     return Result("Missing value for tolerance command");
836   if (found_tokens != 1 && found_tokens != 4)
837     return Result("Invalid number of tolerance parameters provided");
838 
839   if (!token->IsEOS() && !token->IsEOL())
840     return Result("Extra parameter for tolerance command: " +
841                   token->ToOriginalString());
842 
843   return {};
844 }
845 
ProcessPatch()846 Result CommandParser::ProcessPatch() {
847   auto cmd = MakeUnique<PatchParameterVerticesCommand>(pipeline_);
848   cmd->SetLine(tokenizer_->GetCurrentLine());
849 
850   auto token = tokenizer_->NextToken();
851   if (!token->IsString() || token->AsString() != "parameter")
852     return Result("Missing parameter flag to patch command: " +
853                   token->ToOriginalString());
854 
855   token = tokenizer_->NextToken();
856   if (!token->IsString() || token->AsString() != "vertices")
857     return Result("Missing vertices flag to patch command: " +
858                   token->ToOriginalString());
859 
860   token = tokenizer_->NextToken();
861   if (!token->IsInteger())
862     return Result("Invalid count parameter for patch parameter vertices: " +
863                   token->ToOriginalString());
864   cmd->SetControlPointCount(token->AsUint32());
865 
866   token = tokenizer_->NextToken();
867   if (!token->IsEOS() && !token->IsEOL())
868     return Result("Extra parameter for patch parameter vertices command: " +
869                   token->ToOriginalString());
870 
871   commands_.push_back(std::move(cmd));
872   return {};
873 }
874 
ProcessEntryPoint(const std::string & name)875 Result CommandParser::ProcessEntryPoint(const std::string& name) {
876   auto cmd = MakeUnique<EntryPointCommand>(pipeline_);
877   cmd->SetLine(tokenizer_->GetCurrentLine());
878 
879   auto token = tokenizer_->NextToken();
880   if (token->IsEOL() || token->IsEOS())
881     return Result("Missing entrypoint name");
882 
883   if (!token->IsString())
884     return Result("Entrypoint name must be a string: " +
885                   token->ToOriginalString());
886 
887   cmd->SetShaderType(ShaderNameToType(name));
888   cmd->SetEntryPointName(token->AsString());
889 
890   token = tokenizer_->NextToken();
891   if (!token->IsEOS() && !token->IsEOL())
892     return Result("Extra parameter for entrypoint command: " +
893                   token->ToOriginalString());
894 
895   commands_.push_back(std::move(cmd));
896 
897   return {};
898 }
899 
ProcessProbe(bool relative)900 Result CommandParser::ProcessProbe(bool relative) {
901   auto token = tokenizer_->NextToken();
902   if (!token->IsString())
903     return Result("Invalid token in probe command: " +
904                   token->ToOriginalString());
905 
906   // The SSBO syntax is different from probe or probe all so handle specially.
907   if (token->AsString() == "ssbo")
908     return ProcessProbeSSBO();
909 
910   if (pipeline_->GetColorAttachments().empty())
911     return Result("Pipeline missing color buffers. Something went wrong.");
912 
913   // VkScript has a single generated colour buffer which should always be
914   // available.
915   auto* buffer = pipeline_->GetColorAttachments()[0].buffer;
916   if (!buffer)
917     return Result("Pipeline missing color buffers, something went wrong.");
918 
919   auto cmd = MakeUnique<ProbeCommand>(buffer);
920   cmd->SetLine(tokenizer_->GetCurrentLine());
921 
922   cmd->SetTolerances(current_tolerances_);
923   if (relative)
924     cmd->SetRelative();
925 
926   bool is_rect = false;
927   if (token->AsString() == "rect") {
928     is_rect = true;
929     cmd->SetProbeRect();
930 
931     token = tokenizer_->NextToken();
932     if (!token->IsString())
933       return Result("Invalid token in probe command: " +
934                     token->ToOriginalString());
935   } else if (token->AsString() == "all") {
936     cmd->SetWholeWindow();
937     cmd->SetProbeRect();
938 
939     token = tokenizer_->NextToken();
940     if (!token->IsString())
941       return Result("Invalid token in probe command: " +
942                     token->ToOriginalString());
943   }
944 
945   std::string format = token->AsString();
946   if (format != "rgba" && format != "rgb")
947     return Result("Invalid format specified to probe command: " +
948                   token->ToOriginalString());
949 
950   if (format == "rgba")
951     cmd->SetIsRGBA();
952 
953   token = tokenizer_->NextToken();
954   if (!cmd->IsWholeWindow()) {
955     bool got_rect_open_bracket = false;
956     if (token->IsOpenBracket()) {
957       got_rect_open_bracket = true;
958       token = tokenizer_->NextToken();
959     }
960 
961     Result r = token->ConvertToDouble();
962     if (!r.IsSuccess())
963       return r;
964     cmd->SetX(token->AsFloat());
965 
966     token = tokenizer_->NextToken();
967     if (token->IsComma())
968       token = tokenizer_->NextToken();
969 
970     r = token->ConvertToDouble();
971     if (!r.IsSuccess())
972       return r;
973     cmd->SetY(token->AsFloat());
974 
975     if (is_rect) {
976       token = tokenizer_->NextToken();
977       if (token->IsComma())
978         token = tokenizer_->NextToken();
979 
980       r = token->ConvertToDouble();
981       if (!r.IsSuccess())
982         return r;
983       cmd->SetWidth(token->AsFloat());
984 
985       token = tokenizer_->NextToken();
986       if (token->IsComma())
987         token = tokenizer_->NextToken();
988 
989       r = token->ConvertToDouble();
990       if (!r.IsSuccess())
991         return r;
992       cmd->SetHeight(token->AsFloat());
993     }
994 
995     token = tokenizer_->NextToken();
996     if (token->IsCloseBracket()) {
997       // Close bracket without an open
998       if (!got_rect_open_bracket)
999         return Result("Missing open bracket for probe command");
1000 
1001       token = tokenizer_->NextToken();
1002     } else if (got_rect_open_bracket) {
1003       // An open bracket without a close bracket.
1004       return Result("Missing close bracket for probe command");
1005     }
1006   }
1007 
1008   bool got_color_open_bracket = false;
1009   if (token->IsOpenBracket()) {
1010     got_color_open_bracket = true;
1011     token = tokenizer_->NextToken();
1012   }
1013 
1014   Result r = token->ConvertToDouble();
1015   if (!r.IsSuccess())
1016     return r;
1017   cmd->SetR(token->AsFloat());
1018 
1019   token = tokenizer_->NextToken();
1020   if (token->IsComma())
1021     token = tokenizer_->NextToken();
1022 
1023   r = token->ConvertToDouble();
1024   if (!r.IsSuccess())
1025     return r;
1026   cmd->SetG(token->AsFloat());
1027 
1028   token = tokenizer_->NextToken();
1029   if (token->IsComma())
1030     token = tokenizer_->NextToken();
1031 
1032   r = token->ConvertToDouble();
1033   if (!r.IsSuccess())
1034     return r;
1035   cmd->SetB(token->AsFloat());
1036 
1037   if (format == "rgba") {
1038     token = tokenizer_->NextToken();
1039     if (token->IsComma())
1040       token = tokenizer_->NextToken();
1041 
1042     r = token->ConvertToDouble();
1043     if (!r.IsSuccess())
1044       return r;
1045     cmd->SetA(token->AsFloat());
1046   }
1047 
1048   token = tokenizer_->NextToken();
1049   if (token->IsCloseBracket()) {
1050     if (!got_color_open_bracket) {
1051       // Close without an open.
1052       return Result("Missing open bracket for probe command");
1053     }
1054     token = tokenizer_->NextToken();
1055   } else if (got_color_open_bracket) {
1056     // Open bracket without a close.
1057     return Result("Missing close bracket for probe command");
1058   }
1059 
1060   if (!token->IsEOS() && !token->IsEOL())
1061     return Result("Extra parameter to probe command: " +
1062                   token->ToOriginalString());
1063 
1064   commands_.push_back(std::move(cmd));
1065   return {};
1066 }
1067 
ProcessTopology()1068 Result CommandParser::ProcessTopology() {
1069   auto token = tokenizer_->NextToken();
1070   if (token->IsEOS() || token->IsEOL())
1071     return Result("Missing value for topology command");
1072   if (!token->IsString())
1073     return Result("Invalid value for topology command: " +
1074                   token->ToOriginalString());
1075 
1076   Topology topology = Topology::kPatchList;
1077   std::string topo = token->AsString();
1078 
1079   if (topo == "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST")
1080     topology = Topology::kPatchList;
1081   else if (topo == "VK_PRIMITIVE_TOPOLOGY_POINT_LIST")
1082     topology = Topology::kPointList;
1083   else if (topo == "VK_PRIMITIVE_TOPOLOGY_LINE_LIST")
1084     topology = Topology::kLineList;
1085   else if (topo == "VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY")
1086     topology = Topology::kLineListWithAdjacency;
1087   else if (topo == "VK_PRIMITIVE_TOPOLOGY_LINE_STRIP")
1088     topology = Topology::kLineStrip;
1089   else if (topo == "VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY")
1090     topology = Topology::kLineStripWithAdjacency;
1091   else if (topo == "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN")
1092     topology = Topology::kTriangleFan;
1093   else if (topo == "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST")
1094     topology = Topology::kTriangleList;
1095   else if (topo == "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY")
1096     topology = Topology::kTriangleListWithAdjacency;
1097   else if (topo == "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP")
1098     topology = Topology::kTriangleStrip;
1099   else if (topo == "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY")
1100     topology = Topology::kTriangleStripWithAdjacency;
1101   else
1102     return Result("Unknown value for topology command: " +
1103                   token->ToOriginalString());
1104 
1105   token = tokenizer_->NextToken();
1106   if (!token->IsEOS() && !token->IsEOL())
1107     return Result("Extra parameter for topology command: " +
1108                   token->ToOriginalString());
1109 
1110   pipeline_data_.SetTopology(topology);
1111   return {};
1112 }
1113 
ProcessPolygonMode()1114 Result CommandParser::ProcessPolygonMode() {
1115   auto token = tokenizer_->NextToken();
1116   if (token->IsEOS() || token->IsEOL())
1117     return Result("Missing value for polygonMode command");
1118   if (!token->IsString())
1119     return Result("Invalid value for polygonMode command: " +
1120                   token->ToOriginalString());
1121 
1122   PolygonMode mode = PolygonMode::kFill;
1123   std::string m = token->AsString();
1124   if (m == "VK_POLYGON_MODE_FILL")
1125     mode = PolygonMode::kFill;
1126   else if (m == "VK_POLYGON_MODE_LINE")
1127     mode = PolygonMode::kLine;
1128   else if (m == "VK_POLYGON_MODE_POINT")
1129     mode = PolygonMode::kPoint;
1130   else
1131     return Result("Unknown value for polygonMode command: " +
1132                   token->ToOriginalString());
1133 
1134   token = tokenizer_->NextToken();
1135   if (!token->IsEOS() && !token->IsEOL())
1136     return Result("Extra parameter for polygonMode command: " +
1137                   token->ToOriginalString());
1138 
1139   pipeline_data_.SetPolygonMode(mode);
1140   return {};
1141 }
1142 
ProcessLogicOp()1143 Result CommandParser::ProcessLogicOp() {
1144   auto token = tokenizer_->NextToken();
1145   if (token->IsEOS() || token->IsEOL())
1146     return Result("Missing value for logicOp command");
1147   if (!token->IsString())
1148     return Result("Invalid value for logicOp command: " +
1149                   token->ToOriginalString());
1150 
1151   LogicOp op = LogicOp::kClear;
1152   std::string name = token->AsString();
1153   if (name == "VK_LOGIC_OP_CLEAR")
1154     op = LogicOp::kClear;
1155   else if (name == "VK_LOGIC_OP_AND")
1156     op = LogicOp::kAnd;
1157   else if (name == "VK_LOGIC_OP_AND_REVERSE")
1158     op = LogicOp::kAndReverse;
1159   else if (name == "VK_LOGIC_OP_COPY")
1160     op = LogicOp::kCopy;
1161   else if (name == "VK_LOGIC_OP_AND_INVERTED")
1162     op = LogicOp::kAndInverted;
1163   else if (name == "VK_LOGIC_OP_NO_OP")
1164     op = LogicOp::kNoOp;
1165   else if (name == "VK_LOGIC_OP_XOR")
1166     op = LogicOp::kXor;
1167   else if (name == "VK_LOGIC_OP_OR")
1168     op = LogicOp::kOr;
1169   else if (name == "VK_LOGIC_OP_NOR")
1170     op = LogicOp::kNor;
1171   else if (name == "VK_LOGIC_OP_EQUIVALENT")
1172     op = LogicOp::kEquivalent;
1173   else if (name == "VK_LOGIC_OP_INVERT")
1174     op = LogicOp::kInvert;
1175   else if (name == "VK_LOGIC_OP_OR_REVERSE")
1176     op = LogicOp::kOrReverse;
1177   else if (name == "VK_LOGIC_OP_COPY_INVERTED")
1178     op = LogicOp::kCopyInverted;
1179   else if (name == "VK_LOGIC_OP_OR_INVERTED")
1180     op = LogicOp::kOrInverted;
1181   else if (name == "VK_LOGIC_OP_NAND")
1182     op = LogicOp::kNand;
1183   else if (name == "VK_LOGIC_OP_SET")
1184     op = LogicOp::kSet;
1185   else
1186     return Result("Unknown value for logicOp command: " +
1187                   token->ToOriginalString());
1188 
1189   token = tokenizer_->NextToken();
1190   if (!token->IsEOS() && !token->IsEOL())
1191     return Result("Extra parameter for logicOp command: " +
1192                   token->ToOriginalString());
1193 
1194   pipeline_data_.SetLogicOp(op);
1195   return {};
1196 }
1197 
ProcessCullMode()1198 Result CommandParser::ProcessCullMode() {
1199   auto token = tokenizer_->NextToken();
1200   if (token->IsEOS() || token->IsEOL())
1201     return Result("Missing value for cullMode command");
1202   if (!token->IsString())
1203     return Result("Invalid value for cullMode command: " +
1204                   token->ToOriginalString());
1205 
1206   CullMode mode = CullMode::kNone;
1207   while (!token->IsEOS() && !token->IsEOL()) {
1208     std::string name = token->AsString();
1209 
1210     if (name == "|") {
1211       // We treat everything as an |.
1212     } else if (name == "VK_CULL_MODE_FRONT_BIT") {
1213       if (mode == CullMode::kNone)
1214         mode = CullMode::kFront;
1215       else if (mode == CullMode::kBack)
1216         mode = CullMode::kFrontAndBack;
1217     } else if (name == "VK_CULL_MODE_BACK_BIT") {
1218       if (mode == CullMode::kNone)
1219         mode = CullMode::kBack;
1220       else if (mode == CullMode::kFront)
1221         mode = CullMode::kFrontAndBack;
1222     } else if (name == "VK_CULL_MODE_FRONT_AND_BACK") {
1223       mode = CullMode::kFrontAndBack;
1224     } else if (name == "VK_CULL_MODE_NONE") {
1225       // Do nothing ...
1226     } else {
1227       return Result("Unknown value for cullMode command: " +
1228                     token->ToOriginalString());
1229     }
1230 
1231     token = tokenizer_->NextToken();
1232   }
1233 
1234   pipeline_data_.SetCullMode(mode);
1235   return {};
1236 }
1237 
ProcessFrontFace()1238 Result CommandParser::ProcessFrontFace() {
1239   auto token = tokenizer_->NextToken();
1240   if (token->IsEOS() || token->IsEOL())
1241     return Result("Missing value for frontFace command");
1242   if (!token->IsString())
1243     return Result("Invalid value for frontFace command: " +
1244                   token->ToOriginalString());
1245 
1246   FrontFace face = FrontFace::kCounterClockwise;
1247   std::string f = token->AsString();
1248   if (f == "VK_FRONT_FACE_COUNTER_CLOCKWISE")
1249     face = FrontFace::kCounterClockwise;
1250   else if (f == "VK_FRONT_FACE_CLOCKWISE")
1251     face = FrontFace::kClockwise;
1252   else
1253     return Result("Unknown value for frontFace command: " +
1254                   token->ToOriginalString());
1255 
1256   token = tokenizer_->NextToken();
1257   if (!token->IsEOS() && !token->IsEOL())
1258     return Result("Extra parameter for frontFace command: " +
1259                   token->ToOriginalString());
1260 
1261   pipeline_data_.SetFrontFace(face);
1262   return {};
1263 }
1264 
ProcessBooleanPipelineData(const std::string & name,bool * value)1265 Result CommandParser::ProcessBooleanPipelineData(const std::string& name,
1266                                                  bool* value) {
1267   auto token = tokenizer_->NextToken();
1268   if (token->IsEOS() || token->IsEOL())
1269     return Result("Missing value for " + name + " command");
1270   if (!token->IsString())
1271     return Result("Invalid value for " + name +
1272                   " command: " + token->ToOriginalString());
1273 
1274   Result r = ParseBoolean(token->AsString(), value);
1275   if (!r.IsSuccess())
1276     return r;
1277 
1278   token = tokenizer_->NextToken();
1279   if (!token->IsEOS() && !token->IsEOL())
1280     return Result("Extra parameter for " + name +
1281                   " command: " + token->ToOriginalString());
1282 
1283   return {};
1284 }
1285 
ProcessPrimitiveRestartEnable()1286 Result CommandParser::ProcessPrimitiveRestartEnable() {
1287   bool value = false;
1288   Result r = ProcessBooleanPipelineData("primitiveRestartEnable", &value);
1289   if (!r.IsSuccess())
1290     return r;
1291 
1292   pipeline_data_.SetEnablePrimitiveRestart(value);
1293   return {};
1294 }
1295 
ProcessDepthClampEnable()1296 Result CommandParser::ProcessDepthClampEnable() {
1297   bool value = false;
1298   Result r = ProcessBooleanPipelineData("depthClampEnable", &value);
1299   if (!r.IsSuccess())
1300     return r;
1301 
1302   pipeline_data_.SetEnableDepthClamp(value);
1303   return {};
1304 }
1305 
ProcessRasterizerDiscardEnable()1306 Result CommandParser::ProcessRasterizerDiscardEnable() {
1307   bool value = false;
1308   Result r = ProcessBooleanPipelineData("rasterizerDiscardEnable", &value);
1309   if (!r.IsSuccess())
1310     return r;
1311 
1312   pipeline_data_.SetEnableRasterizerDiscard(value);
1313   return {};
1314 }
1315 
ProcessDepthBiasEnable()1316 Result CommandParser::ProcessDepthBiasEnable() {
1317   bool value = false;
1318   Result r = ProcessBooleanPipelineData("depthBiasEnable", &value);
1319   if (!r.IsSuccess())
1320     return r;
1321 
1322   pipeline_data_.SetEnableDepthBias(value);
1323   return {};
1324 }
1325 
ProcessLogicOpEnable()1326 Result CommandParser::ProcessLogicOpEnable() {
1327   bool value = false;
1328   Result r = ProcessBooleanPipelineData("logicOpEnable", &value);
1329   if (!r.IsSuccess())
1330     return r;
1331 
1332   pipeline_data_.SetEnableLogicOp(value);
1333   return {};
1334 }
1335 
ProcessBlendEnable()1336 Result CommandParser::ProcessBlendEnable() {
1337   bool value = false;
1338   Result r = ProcessBooleanPipelineData("blendEnable", &value);
1339   if (!r.IsSuccess())
1340     return r;
1341 
1342   pipeline_data_.SetEnableBlend(value);
1343   return {};
1344 }
1345 
ProcessDepthTestEnable()1346 Result CommandParser::ProcessDepthTestEnable() {
1347   bool value = false;
1348   Result r = ProcessBooleanPipelineData("depthTestEnable", &value);
1349   if (!r.IsSuccess())
1350     return r;
1351 
1352   pipeline_data_.SetEnableDepthTest(value);
1353   return {};
1354 }
1355 
ProcessDepthWriteEnable()1356 Result CommandParser::ProcessDepthWriteEnable() {
1357   bool value = false;
1358   Result r = ProcessBooleanPipelineData("depthWriteEnable", &value);
1359   if (!r.IsSuccess())
1360     return r;
1361 
1362   pipeline_data_.SetEnableDepthWrite(value);
1363   return {};
1364 }
1365 
ProcessDepthBoundsTestEnable()1366 Result CommandParser::ProcessDepthBoundsTestEnable() {
1367   bool value = false;
1368   Result r = ProcessBooleanPipelineData("depthBoundsTestEnable", &value);
1369   if (!r.IsSuccess())
1370     return r;
1371 
1372   pipeline_data_.SetEnableDepthBoundsTest(value);
1373   return {};
1374 }
1375 
ProcessStencilTestEnable()1376 Result CommandParser::ProcessStencilTestEnable() {
1377   bool value = false;
1378   Result r = ProcessBooleanPipelineData("stencilTestEnable", &value);
1379   if (!r.IsSuccess())
1380     return r;
1381 
1382   pipeline_data_.SetEnableStencilTest(value);
1383   return {};
1384 }
1385 
ProcessFloatPipelineData(const std::string & name,float * value)1386 Result CommandParser::ProcessFloatPipelineData(const std::string& name,
1387                                                float* value) {
1388   assert(value);
1389 
1390   auto token = tokenizer_->NextToken();
1391   if (token->IsEOS() || token->IsEOL())
1392     return Result("Missing value for " + name + " command");
1393 
1394   Result r = token->ConvertToDouble();
1395   if (!r.IsSuccess())
1396     return r;
1397 
1398   *value = token->AsFloat();
1399 
1400   token = tokenizer_->NextToken();
1401   if (!token->IsEOS() && !token->IsEOL())
1402     return Result("Extra parameter for " + name +
1403                   " command: " + token->ToOriginalString());
1404 
1405   return {};
1406 }
1407 
ProcessDepthBiasConstantFactor()1408 Result CommandParser::ProcessDepthBiasConstantFactor() {
1409   float value = 0.0;
1410   Result r = ProcessFloatPipelineData("depthBiasConstantFactor", &value);
1411   if (!r.IsSuccess())
1412     return r;
1413 
1414   pipeline_data_.SetDepthBiasConstantFactor(value);
1415   return {};
1416 }
1417 
ProcessDepthBiasClamp()1418 Result CommandParser::ProcessDepthBiasClamp() {
1419   float value = 0.0;
1420   Result r = ProcessFloatPipelineData("depthBiasClamp", &value);
1421   if (!r.IsSuccess())
1422     return r;
1423 
1424   pipeline_data_.SetDepthBiasClamp(value);
1425   return {};
1426 }
1427 
ProcessDepthBiasSlopeFactor()1428 Result CommandParser::ProcessDepthBiasSlopeFactor() {
1429   float value = 0.0;
1430   Result r = ProcessFloatPipelineData("depthBiasSlopeFactor", &value);
1431   if (!r.IsSuccess())
1432     return r;
1433 
1434   pipeline_data_.SetDepthBiasSlopeFactor(value);
1435   return {};
1436 }
1437 
ProcessLineWidth()1438 Result CommandParser::ProcessLineWidth() {
1439   float value = 0.0;
1440   Result r = ProcessFloatPipelineData("lineWidth", &value);
1441   if (!r.IsSuccess())
1442     return r;
1443 
1444   pipeline_data_.SetLineWidth(value);
1445   return {};
1446 }
1447 
ProcessMinDepthBounds()1448 Result CommandParser::ProcessMinDepthBounds() {
1449   float value = 0.0;
1450   Result r = ProcessFloatPipelineData("minDepthBounds", &value);
1451   if (!r.IsSuccess())
1452     return r;
1453 
1454   pipeline_data_.SetMinDepthBounds(value);
1455   return {};
1456 }
1457 
ProcessMaxDepthBounds()1458 Result CommandParser::ProcessMaxDepthBounds() {
1459   float value = 0.0;
1460   Result r = ProcessFloatPipelineData("maxDepthBounds", &value);
1461   if (!r.IsSuccess())
1462     return r;
1463 
1464   pipeline_data_.SetMaxDepthBounds(value);
1465   return {};
1466 }
1467 
ParseBlendFactorName(const std::string & name,BlendFactor * factor)1468 Result CommandParser::ParseBlendFactorName(const std::string& name,
1469                                            BlendFactor* factor) {
1470   assert(factor);
1471 
1472   if (name == "VK_BLEND_FACTOR_ZERO")
1473     *factor = BlendFactor::kZero;
1474   else if (name == "VK_BLEND_FACTOR_ONE")
1475     *factor = BlendFactor::kOne;
1476   else if (name == "VK_BLEND_FACTOR_SRC_COLOR")
1477     *factor = BlendFactor::kSrcColor;
1478   else if (name == "VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR")
1479     *factor = BlendFactor::kOneMinusSrcColor;
1480   else if (name == "VK_BLEND_FACTOR_DST_COLOR")
1481     *factor = BlendFactor::kDstColor;
1482   else if (name == "VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR")
1483     *factor = BlendFactor::kOneMinusDstColor;
1484   else if (name == "VK_BLEND_FACTOR_SRC_ALPHA")
1485     *factor = BlendFactor::kSrcAlpha;
1486   else if (name == "VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA")
1487     *factor = BlendFactor::kOneMinusSrcAlpha;
1488   else if (name == "VK_BLEND_FACTOR_DST_ALPHA")
1489     *factor = BlendFactor::kDstAlpha;
1490   else if (name == "VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA")
1491     *factor = BlendFactor::kOneMinusDstAlpha;
1492   else if (name == "VK_BLEND_FACTOR_CONSTANT_COLOR")
1493     *factor = BlendFactor::kConstantColor;
1494   else if (name == "VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR")
1495     *factor = BlendFactor::kOneMinusConstantColor;
1496   else if (name == "VK_BLEND_FACTOR_CONSTANT_ALPHA")
1497     *factor = BlendFactor::kConstantAlpha;
1498   else if (name == "VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA")
1499     *factor = BlendFactor::kOneMinusConstantAlpha;
1500   else if (name == "VK_BLEND_FACTOR_SRC_ALPHA_SATURATE")
1501     *factor = BlendFactor::kSrcAlphaSaturate;
1502   else if (name == "VK_BLEND_FACTOR_SRC1_COLOR")
1503     *factor = BlendFactor::kSrc1Color;
1504   else if (name == "VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR")
1505     *factor = BlendFactor::kOneMinusSrc1Color;
1506   else if (name == "VK_BLEND_FACTOR_SRC1_ALPHA")
1507     *factor = BlendFactor::kSrc1Alpha;
1508   else if (name == "VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA")
1509     *factor = BlendFactor::kOneMinusSrc1Alpha;
1510   else
1511     return Result("Unknown BlendFactor provided: " + name);
1512 
1513   return {};
1514 }
1515 
ParseBlendFactor(const std::string & name,BlendFactor * factor)1516 Result CommandParser::ParseBlendFactor(const std::string& name,
1517                                        BlendFactor* factor) {
1518   auto token = tokenizer_->NextToken();
1519   if (token->IsEOL() || token->IsEOS())
1520     return Result(std::string("Missing parameter for ") + name + " command");
1521   if (!token->IsString())
1522     return Result(std::string("Invalid parameter for ") + name +
1523                   " command: " + token->ToOriginalString());
1524 
1525   Result r = ParseBlendFactorName(token->AsString(), factor);
1526   if (!r.IsSuccess())
1527     return r;
1528 
1529   token = tokenizer_->NextToken();
1530   if (!token->IsEOS() && !token->IsEOL())
1531     return Result(std::string("Extra parameter for ") + name +
1532                   " command: " + token->ToOriginalString());
1533 
1534   return {};
1535 }
1536 
ProcessSrcAlphaBlendFactor()1537 Result CommandParser::ProcessSrcAlphaBlendFactor() {
1538   BlendFactor factor = BlendFactor::kZero;
1539   Result r = ParseBlendFactor("srcAlphaBlendFactor", &factor);
1540   if (!r.IsSuccess())
1541     return r;
1542 
1543   pipeline_data_.SetSrcAlphaBlendFactor(factor);
1544   return {};
1545 }
1546 
ProcessDstAlphaBlendFactor()1547 Result CommandParser::ProcessDstAlphaBlendFactor() {
1548   BlendFactor factor = BlendFactor::kZero;
1549   Result r = ParseBlendFactor("dstAlphaBlendFactor", &factor);
1550   if (!r.IsSuccess())
1551     return r;
1552 
1553   pipeline_data_.SetDstAlphaBlendFactor(factor);
1554   return {};
1555 }
1556 
ProcessSrcColorBlendFactor()1557 Result CommandParser::ProcessSrcColorBlendFactor() {
1558   BlendFactor factor = BlendFactor::kZero;
1559   Result r = ParseBlendFactor("srcColorBlendFactor", &factor);
1560   if (!r.IsSuccess())
1561     return r;
1562 
1563   pipeline_data_.SetSrcColorBlendFactor(factor);
1564   return {};
1565 }
1566 
ProcessDstColorBlendFactor()1567 Result CommandParser::ProcessDstColorBlendFactor() {
1568   BlendFactor factor = BlendFactor::kZero;
1569   Result r = ParseBlendFactor("dstColorBlendFactor", &factor);
1570   if (!r.IsSuccess())
1571     return r;
1572 
1573   pipeline_data_.SetDstColorBlendFactor(factor);
1574   return {};
1575 }
1576 
ParseBlendOpName(const std::string & name,BlendOp * op)1577 Result CommandParser::ParseBlendOpName(const std::string& name, BlendOp* op) {
1578   assert(op);
1579 
1580   if (name == "VK_BLEND_OP_ADD")
1581     *op = BlendOp::kAdd;
1582   else if (name == "VK_BLEND_OP_ADD")
1583     *op = BlendOp::kAdd;
1584   else if (name == "VK_BLEND_OP_SUBTRACT")
1585     *op = BlendOp::kSubtract;
1586   else if (name == "VK_BLEND_OP_REVERSE_SUBTRACT")
1587     *op = BlendOp::kReverseSubtract;
1588   else if (name == "VK_BLEND_OP_MIN")
1589     *op = BlendOp::kMin;
1590   else if (name == "VK_BLEND_OP_MAX")
1591     *op = BlendOp::kMax;
1592   else if (name == "VK_BLEND_OP_ZERO_EXT")
1593     *op = BlendOp::kZero;
1594   else if (name == "VK_BLEND_OP_SRC_EXT")
1595     *op = BlendOp::kSrc;
1596   else if (name == "VK_BLEND_OP_DST_EXT")
1597     *op = BlendOp::kDst;
1598   else if (name == "VK_BLEND_OP_SRC_OVER_EXT")
1599     *op = BlendOp::kSrcOver;
1600   else if (name == "VK_BLEND_OP_DST_OVER_EXT")
1601     *op = BlendOp::kDstOver;
1602   else if (name == "VK_BLEND_OP_SRC_IN_EXT")
1603     *op = BlendOp::kSrcIn;
1604   else if (name == "VK_BLEND_OP_DST_IN_EXT")
1605     *op = BlendOp::kDstIn;
1606   else if (name == "VK_BLEND_OP_SRC_OUT_EXT")
1607     *op = BlendOp::kSrcOut;
1608   else if (name == "VK_BLEND_OP_DST_OUT_EXT")
1609     *op = BlendOp::kDstOut;
1610   else if (name == "VK_BLEND_OP_SRC_ATOP_EXT")
1611     *op = BlendOp::kSrcAtop;
1612   else if (name == "VK_BLEND_OP_DST_ATOP_EXT")
1613     *op = BlendOp::kDstAtop;
1614   else if (name == "VK_BLEND_OP_XOR_EXT")
1615     *op = BlendOp::kXor;
1616   else if (name == "VK_BLEND_OP_MULTIPLY_EXT")
1617     *op = BlendOp::kMultiply;
1618   else if (name == "VK_BLEND_OP_SCREEN_EXT")
1619     *op = BlendOp::kScreen;
1620   else if (name == "VK_BLEND_OP_OVERLAY_EXT")
1621     *op = BlendOp::kOverlay;
1622   else if (name == "VK_BLEND_OP_DARKEN_EXT")
1623     *op = BlendOp::kDarken;
1624   else if (name == "VK_BLEND_OP_LIGHTEN_EXT")
1625     *op = BlendOp::kLighten;
1626   else if (name == "VK_BLEND_OP_COLORDODGE_EXT")
1627     *op = BlendOp::kColorDodge;
1628   else if (name == "VK_BLEND_OP_COLORBURN_EXT")
1629     *op = BlendOp::kColorBurn;
1630   else if (name == "VK_BLEND_OP_HARDLIGHT_EXT")
1631     *op = BlendOp::kHardLight;
1632   else if (name == "VK_BLEND_OP_SOFTLIGHT_EXT")
1633     *op = BlendOp::kSoftLight;
1634   else if (name == "VK_BLEND_OP_DIFFERENCE_EXT")
1635     *op = BlendOp::kDifference;
1636   else if (name == "VK_BLEND_OP_EXCLUSION_EXT")
1637     *op = BlendOp::kExclusion;
1638   else if (name == "VK_BLEND_OP_INVERT_EXT")
1639     *op = BlendOp::kInvert;
1640   else if (name == "VK_BLEND_OP_INVERT_RGB_EXT")
1641     *op = BlendOp::kInvertRGB;
1642   else if (name == "VK_BLEND_OP_LINEARDODGE_EXT")
1643     *op = BlendOp::kLinearDodge;
1644   else if (name == "VK_BLEND_OP_LINEARBURN_EXT")
1645     *op = BlendOp::kLinearBurn;
1646   else if (name == "VK_BLEND_OP_VIVIDLIGHT_EXT")
1647     *op = BlendOp::kVividLight;
1648   else if (name == "VK_BLEND_OP_LINEARLIGHT_EXT")
1649     *op = BlendOp::kLinearLight;
1650   else if (name == "VK_BLEND_OP_PINLIGHT_EXT")
1651     *op = BlendOp::kPinLight;
1652   else if (name == "VK_BLEND_OP_HARDMIX_EXT")
1653     *op = BlendOp::kHardMix;
1654   else if (name == "VK_BLEND_OP_HSL_HUE_EXT")
1655     *op = BlendOp::kHslHue;
1656   else if (name == "VK_BLEND_OP_HSL_SATURATION_EXT")
1657     *op = BlendOp::kHslSaturation;
1658   else if (name == "VK_BLEND_OP_HSL_COLOR_EXT")
1659     *op = BlendOp::kHslColor;
1660   else if (name == "VK_BLEND_OP_HSL_LUMINOSITY_EXT")
1661     *op = BlendOp::kHslLuminosity;
1662   else if (name == "VK_BLEND_OP_PLUS_EXT")
1663     *op = BlendOp::kPlus;
1664   else if (name == "VK_BLEND_OP_PLUS_CLAMPED_EXT")
1665     *op = BlendOp::kPlusClamped;
1666   else if (name == "VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT")
1667     *op = BlendOp::kPlusClampedAlpha;
1668   else if (name == "VK_BLEND_OP_PLUS_DARKER_EXT")
1669     *op = BlendOp::kPlusDarker;
1670   else if (name == "VK_BLEND_OP_MINUS_EXT")
1671     *op = BlendOp::kMinus;
1672   else if (name == "VK_BLEND_OP_MINUS_CLAMPED_EXT")
1673     *op = BlendOp::kMinusClamped;
1674   else if (name == "VK_BLEND_OP_CONTRAST_EXT")
1675     *op = BlendOp::kContrast;
1676   else if (name == "VK_BLEND_OP_INVERT_OVG_EXT")
1677     *op = BlendOp::kInvertOvg;
1678   else if (name == "VK_BLEND_OP_RED_EXT")
1679     *op = BlendOp::kRed;
1680   else if (name == "VK_BLEND_OP_GREEN_EXT")
1681     *op = BlendOp::kGreen;
1682   else if (name == "VK_BLEND_OP_BLUE_EXT")
1683     *op = BlendOp::kBlue;
1684   else
1685     return Result("Unknown BlendOp provided: " + name);
1686 
1687   return {};
1688 }
1689 
ParseBlendOp(const std::string & name,BlendOp * op)1690 Result CommandParser::ParseBlendOp(const std::string& name, BlendOp* op) {
1691   auto token = tokenizer_->NextToken();
1692   if (token->IsEOL() || token->IsEOS())
1693     return Result(std::string("Missing parameter for ") + name + " command");
1694   if (!token->IsString())
1695     return Result(std::string("Invalid parameter for ") + name +
1696                   " command: " + token->ToOriginalString());
1697 
1698   Result r = ParseBlendOpName(token->AsString(), op);
1699   if (!r.IsSuccess())
1700     return r;
1701 
1702   token = tokenizer_->NextToken();
1703   if (!token->IsEOS() && !token->IsEOL())
1704     return Result(std::string("Extra parameter for ") + name +
1705                   " command: " + token->ToOriginalString());
1706 
1707   return {};
1708 }
1709 
ProcessColorBlendOp()1710 Result CommandParser::ProcessColorBlendOp() {
1711   BlendOp op = BlendOp::kAdd;
1712   Result r = ParseBlendOp("colorBlendOp", &op);
1713   if (!r.IsSuccess())
1714     return r;
1715 
1716   pipeline_data_.SetColorBlendOp(op);
1717   return {};
1718 }
1719 
ProcessAlphaBlendOp()1720 Result CommandParser::ProcessAlphaBlendOp() {
1721   BlendOp op = BlendOp::kAdd;
1722   Result r = ParseBlendOp("alphaBlendOp", &op);
1723   if (!r.IsSuccess())
1724     return r;
1725 
1726   pipeline_data_.SetAlphaBlendOp(op);
1727   return {};
1728 }
1729 
ParseCompareOp(const std::string & name,CompareOp * op)1730 Result CommandParser::ParseCompareOp(const std::string& name, CompareOp* op) {
1731   auto token = tokenizer_->NextToken();
1732   if (token->IsEOL() || token->IsEOS())
1733     return Result(std::string("Missing parameter for ") + name + " command");
1734   if (!token->IsString())
1735     return Result(std::string("Invalid parameter for ") + name +
1736                   " command: " + token->ToOriginalString());
1737 
1738   Result r = ParseCompareOpName(token->AsString(), op);
1739   if (!r.IsSuccess())
1740     return r;
1741 
1742   token = tokenizer_->NextToken();
1743   if (!token->IsEOS() && !token->IsEOL())
1744     return Result(std::string("Extra parameter for ") + name +
1745                   " command: " + token->ToOriginalString());
1746 
1747   return {};
1748 }
1749 
ParseCompareOpName(const std::string & name,CompareOp * op)1750 Result CommandParser::ParseCompareOpName(const std::string& name,
1751                                          CompareOp* op) {
1752   assert(op);
1753 
1754   if (name == "VK_COMPARE_OP_NEVER")
1755     *op = CompareOp::kNever;
1756   else if (name == "VK_COMPARE_OP_LESS")
1757     *op = CompareOp::kLess;
1758   else if (name == "VK_COMPARE_OP_EQUAL")
1759     *op = CompareOp::kEqual;
1760   else if (name == "VK_COMPARE_OP_LESS_OR_EQUAL")
1761     *op = CompareOp::kLessOrEqual;
1762   else if (name == "VK_COMPARE_OP_GREATER")
1763     *op = CompareOp::kGreater;
1764   else if (name == "VK_COMPARE_OP_NOT_EQUAL")
1765     *op = CompareOp::kNotEqual;
1766   else if (name == "VK_COMPARE_OP_GREATER_OR_EQUAL")
1767     *op = CompareOp::kGreaterOrEqual;
1768   else if (name == "VK_COMPARE_OP_ALWAYS")
1769     *op = CompareOp::kAlways;
1770   else
1771     return Result("Unknown CompareOp provided: " + name);
1772 
1773   return {};
1774 }
1775 
ProcessDepthCompareOp()1776 Result CommandParser::ProcessDepthCompareOp() {
1777   CompareOp op = CompareOp::kNever;
1778   Result r = ParseCompareOp("depthCompareOp", &op);
1779   if (!r.IsSuccess())
1780     return r;
1781 
1782   pipeline_data_.SetDepthCompareOp(op);
1783   return {};
1784 }
1785 
ProcessFrontCompareOp()1786 Result CommandParser::ProcessFrontCompareOp() {
1787   CompareOp op = CompareOp::kNever;
1788   Result r = ParseCompareOp("front.compareOp", &op);
1789   if (!r.IsSuccess())
1790     return r;
1791 
1792   pipeline_data_.SetFrontCompareOp(op);
1793   return {};
1794 }
1795 
ProcessBackCompareOp()1796 Result CommandParser::ProcessBackCompareOp() {
1797   CompareOp op = CompareOp::kNever;
1798   Result r = ParseCompareOp("back.compareOp", &op);
1799   if (!r.IsSuccess())
1800     return r;
1801 
1802   pipeline_data_.SetBackCompareOp(op);
1803   return {};
1804 }
1805 
ParseStencilOp(const std::string & name,StencilOp * op)1806 Result CommandParser::ParseStencilOp(const std::string& name, StencilOp* op) {
1807   auto token = tokenizer_->NextToken();
1808   if (token->IsEOL() || token->IsEOS())
1809     return Result(std::string("Missing parameter for ") + name + " command");
1810   if (!token->IsString())
1811     return Result(std::string("Invalid parameter for ") + name +
1812                   " command: " + token->ToOriginalString());
1813 
1814   Result r = ParseStencilOpName(token->AsString(), op);
1815   if (!r.IsSuccess())
1816     return r;
1817 
1818   token = tokenizer_->NextToken();
1819   if (!token->IsEOS() && !token->IsEOL())
1820     return Result(std::string("Extra parameter for ") + name +
1821                   " command: " + token->ToOriginalString());
1822 
1823   return {};
1824 }
1825 
ParseStencilOpName(const std::string & name,StencilOp * op)1826 Result CommandParser::ParseStencilOpName(const std::string& name,
1827                                          StencilOp* op) {
1828   assert(op);
1829 
1830   if (name == "VK_STENCIL_OP_KEEP")
1831     *op = StencilOp::kKeep;
1832   else if (name == "VK_STENCIL_OP_ZERO")
1833     *op = StencilOp::kZero;
1834   else if (name == "VK_STENCIL_OP_REPLACE")
1835     *op = StencilOp::kReplace;
1836   else if (name == "VK_STENCIL_OP_INCREMENT_AND_CLAMP")
1837     *op = StencilOp::kIncrementAndClamp;
1838   else if (name == "VK_STENCIL_OP_DECREMENT_AND_CLAMP")
1839     *op = StencilOp::kDecrementAndClamp;
1840   else if (name == "VK_STENCIL_OP_INVERT")
1841     *op = StencilOp::kInvert;
1842   else if (name == "VK_STENCIL_OP_INCREMENT_AND_WRAP")
1843     *op = StencilOp::kIncrementAndWrap;
1844   else if (name == "VK_STENCIL_OP_DECREMENT_AND_WRAP")
1845     *op = StencilOp::kDecrementAndWrap;
1846   else
1847     return Result("Unknown StencilOp provided: " + name);
1848 
1849   return {};
1850 }
1851 
ProcessFrontFailOp()1852 Result CommandParser::ProcessFrontFailOp() {
1853   StencilOp op = StencilOp::kKeep;
1854   Result r = ParseStencilOp("front.failOp", &op);
1855   if (!r.IsSuccess())
1856     return r;
1857 
1858   pipeline_data_.SetFrontFailOp(op);
1859   return {};
1860 }
1861 
ProcessFrontPassOp()1862 Result CommandParser::ProcessFrontPassOp() {
1863   StencilOp op = StencilOp::kKeep;
1864   Result r = ParseStencilOp("front.passOp", &op);
1865   if (!r.IsSuccess())
1866     return r;
1867 
1868   pipeline_data_.SetFrontPassOp(op);
1869   return {};
1870 }
1871 
ProcessFrontDepthFailOp()1872 Result CommandParser::ProcessFrontDepthFailOp() {
1873   StencilOp op = StencilOp::kKeep;
1874   Result r = ParseStencilOp("front.depthFailOp", &op);
1875   if (!r.IsSuccess())
1876     return r;
1877 
1878   pipeline_data_.SetFrontDepthFailOp(op);
1879   return {};
1880 }
1881 
ProcessBackFailOp()1882 Result CommandParser::ProcessBackFailOp() {
1883   StencilOp op = StencilOp::kKeep;
1884   Result r = ParseStencilOp("back.failOp", &op);
1885   if (!r.IsSuccess())
1886     return r;
1887 
1888   pipeline_data_.SetBackFailOp(op);
1889   return {};
1890 }
1891 
ProcessBackPassOp()1892 Result CommandParser::ProcessBackPassOp() {
1893   StencilOp op = StencilOp::kKeep;
1894   Result r = ParseStencilOp("back.passOp", &op);
1895   if (!r.IsSuccess())
1896     return r;
1897 
1898   pipeline_data_.SetBackPassOp(op);
1899   return {};
1900 }
1901 
ProcessBackDepthFailOp()1902 Result CommandParser::ProcessBackDepthFailOp() {
1903   StencilOp op = StencilOp::kKeep;
1904   Result r = ParseStencilOp("back.depthFailOp", &op);
1905   if (!r.IsSuccess())
1906     return r;
1907 
1908   pipeline_data_.SetBackDepthFailOp(op);
1909   return {};
1910 }
1911 
ProcessFrontCompareMask()1912 Result CommandParser::ProcessFrontCompareMask() {
1913   return Result("front.compareMask not implemented");
1914 }
1915 
ProcessFrontWriteMask()1916 Result CommandParser::ProcessFrontWriteMask() {
1917   return Result("front.writeMask not implemented");
1918 }
1919 
ProcessBackCompareMask()1920 Result CommandParser::ProcessBackCompareMask() {
1921   return Result("back.compareMask not implemented");
1922 }
1923 
ProcessBackWriteMask()1924 Result CommandParser::ProcessBackWriteMask() {
1925   return Result("back.writeMask not implemented");
1926 }
1927 
ProcessFrontReference()1928 Result CommandParser::ProcessFrontReference() {
1929   auto token = tokenizer_->NextToken();
1930   if (token->IsEOL() || token->IsEOS())
1931     return Result("Missing parameter for front.reference command");
1932   if (!token->IsInteger())
1933     return Result("Invalid parameter for front.reference command: " +
1934                   token->ToOriginalString());
1935 
1936   pipeline_data_.SetFrontReference(token->AsUint32());
1937 
1938   token = tokenizer_->NextToken();
1939   if (!token->IsEOS() && !token->IsEOL())
1940     return Result("Extra parameter for front.reference command: " +
1941                   token->ToOriginalString());
1942 
1943   return {};
1944 }
1945 
ProcessBackReference()1946 Result CommandParser::ProcessBackReference() {
1947   auto token = tokenizer_->NextToken();
1948   if (token->IsEOL() || token->IsEOS())
1949     return Result("Missing parameter for back.reference command");
1950   if (!token->IsInteger())
1951     return Result("Invalid parameter for back.reference command: " +
1952                   token->ToOriginalString());
1953 
1954   pipeline_data_.SetBackReference(token->AsUint32());
1955 
1956   token = tokenizer_->NextToken();
1957   if (!token->IsEOS() && !token->IsEOL())
1958     return Result("Extra parameter for back.reference command: " +
1959                   token->ToOriginalString());
1960 
1961   return {};
1962 }
1963 
ProcessColorWriteMask()1964 Result CommandParser::ProcessColorWriteMask() {
1965   auto token = tokenizer_->NextToken();
1966   if (token->IsEOS() || token->IsEOL())
1967     return Result("Missing parameter for colorWriteMask command");
1968   if (!token->IsString())
1969     return Result("Invalid parameter for colorWriteMask command: " +
1970                   token->ToOriginalString());
1971 
1972   uint8_t mask = 0;
1973   while (!token->IsEOS() && !token->IsEOL()) {
1974     std::string name = token->AsString();
1975 
1976     if (name == "|") {
1977       // We treat everything as an |.
1978     } else if (name == "VK_COLOR_COMPONENT_R_BIT") {
1979       mask |= kColorMaskR;
1980     } else if (name == "VK_COLOR_COMPONENT_G_BIT") {
1981       mask |= kColorMaskG;
1982     } else if (name == "VK_COLOR_COMPONENT_B_BIT") {
1983       mask |= kColorMaskB;
1984     } else if (name == "VK_COLOR_COMPONENT_A_BIT") {
1985       mask |= kColorMaskA;
1986     } else {
1987       return Result("Unknown parameter for colorWriteMask command: " + name);
1988     }
1989 
1990     token = tokenizer_->NextToken();
1991   }
1992 
1993   pipeline_data_.SetColorWriteMask(mask);
1994   return {};
1995 }
1996 
ParseComparator(const std::string & name,ProbeSSBOCommand::Comparator * op)1997 Result CommandParser::ParseComparator(const std::string& name,
1998                                       ProbeSSBOCommand::Comparator* op) {
1999   if (name == "==")
2000     *op = ProbeSSBOCommand::Comparator::kEqual;
2001   else if (name == "!=")
2002     *op = ProbeSSBOCommand::Comparator::kNotEqual;
2003   else if (name == "~=")
2004     *op = ProbeSSBOCommand::Comparator::kFuzzyEqual;
2005   else if (name == "<")
2006     *op = ProbeSSBOCommand::Comparator::kLess;
2007   else if (name == "<=")
2008     *op = ProbeSSBOCommand::Comparator::kLessOrEqual;
2009   else if (name == ">")
2010     *op = ProbeSSBOCommand::Comparator::kGreater;
2011   else if (name == ">=")
2012     *op = ProbeSSBOCommand::Comparator::kGreaterOrEqual;
2013   else
2014     return Result("Invalid comparator: " + name);
2015   return {};
2016 }
2017 
ProcessProbeSSBO()2018 Result CommandParser::ProcessProbeSSBO() {
2019   size_t cur_line = tokenizer_->GetCurrentLine();
2020 
2021   auto token = tokenizer_->NextToken();
2022   if (token->IsEOL() || token->IsEOS())
2023     return Result("Missing values for probe ssbo command");
2024   if (!token->IsString())
2025     return Result("Invalid type for probe ssbo command: " +
2026                   token->ToOriginalString());
2027 
2028   DatumTypeParser tp;
2029   auto type = tp.Parse(token->AsString());
2030   if (!type)
2031     return Result("Invalid type provided: " + token->AsString());
2032 
2033   token = tokenizer_->NextToken();
2034   if (!token->IsInteger())
2035     return Result("Invalid binding value for probe ssbo command: " +
2036                   token->ToOriginalString());
2037 
2038   uint32_t val = token->AsUint32();
2039 
2040   uint32_t set = 0;
2041   uint32_t binding = 0;
2042   token = tokenizer_->NextToken();
2043   if (token->IsString()) {
2044     auto& str = token->AsString();
2045     if (str.size() >= 2 && str[0] == ':') {
2046       set = val;
2047 
2048       auto substr = str.substr(1, str.size());
2049       uint64_t binding_val = strtoul(substr.c_str(), nullptr, 10);
2050       if (binding_val > std::numeric_limits<uint32_t>::max())
2051         return Result("binding value too large in probe ssbo command: " +
2052                       token->ToOriginalString());
2053 
2054       binding = static_cast<uint32_t>(binding_val);
2055     } else {
2056       return Result("Invalid value for probe ssbo command: " +
2057                     token->ToOriginalString());
2058     }
2059 
2060     token = tokenizer_->NextToken();
2061   } else {
2062     binding = val;
2063   }
2064 
2065   auto* buffer = pipeline_->GetBufferForBinding(set, binding);
2066   if (!buffer) {
2067     return Result("unable to find buffer at descriptor set " +
2068                   std::to_string(set) + " and binding " +
2069                   std::to_string(binding));
2070   }
2071 
2072   auto fmt = MakeUnique<Format>(type.get());
2073   if (buffer->FormatIsDefault() || !buffer->GetFormat()) {
2074     buffer->SetFormat(fmt.get());
2075   } else if (buffer->GetFormat() && !buffer->GetFormat()->Equal(fmt.get())) {
2076     return Result("probe format does not match buffer format");
2077   }
2078 
2079   auto cmd = MakeUnique<ProbeSSBOCommand>(buffer);
2080   cmd->SetLine(cur_line);
2081   cmd->SetTolerances(current_tolerances_);
2082   cmd->SetFormat(fmt.get());
2083   cmd->SetDescriptorSet(set);
2084   cmd->SetBinding(binding);
2085 
2086   script_->RegisterFormat(std::move(fmt));
2087   script_->RegisterType(std::move(type));
2088 
2089   if (!token->IsInteger())
2090     return Result("Invalid offset for probe ssbo command: " +
2091                   token->ToOriginalString());
2092 
2093   cmd->SetOffset(token->AsUint32());
2094 
2095   token = tokenizer_->NextToken();
2096   if (!token->IsString())
2097     return Result("Invalid comparator for probe ssbo command: " +
2098                   token->ToOriginalString());
2099 
2100   ProbeSSBOCommand::Comparator comp = ProbeSSBOCommand::Comparator::kEqual;
2101   Result r = ParseComparator(token->AsString(), &comp);
2102   if (!r.IsSuccess())
2103     return r;
2104 
2105   cmd->SetComparator(comp);
2106 
2107   std::vector<Value> values;
2108   r = ParseValues("probe ssbo", cmd->GetFormat(), &values);
2109   if (!r.IsSuccess())
2110     return r;
2111 
2112   cmd->SetValues(std::move(values));
2113 
2114   commands_.push_back(std::move(cmd));
2115   return {};
2116 }
2117 
2118 }  // namespace vkscript
2119 }  // namespace amber
2120