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