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