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