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