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