aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/amber_script.md8
-rw-r--r--src/amber.cc6
-rw-r--r--src/amberscript/parser.cc101
-rw-r--r--src/amberscript/parser.h9
-rw-r--r--src/amberscript/parser_test.cc62
-rw-r--r--src/executor.cc18
-rw-r--r--tests/cases/expect_eq.amber17
7 files changed, 201 insertions, 20 deletions
diff --git a/docs/amber_script.md b/docs/amber_script.md
index 5c29110..de63afd 100644
--- a/docs/amber_script.md
+++ b/docs/amber_script.md
@@ -313,14 +313,14 @@ CLEAR <pipeline>
* EQ\_RGBA
```
-# Checks that |buffer_name| at |x|, |y| has the given |value|s when compared
+# Checks that |buffer_name| at |x| has the given |value|s when compared
# with the given |comparator|.
-EXPECT <buffer_name> IDX <x> <y> <comparator> <value>+
+EXPECT <buffer_name> IDX <x> <comparator> <value>+
-# Checks that |buffer_name| at |x|, |y| has values within |tolerance| of |value|
+# Checks that |buffer_name| at |x| has values within |tolerance| of |value|
# when compared with the given |comparator|. The |tolerance| can be specified
# as 1-4 float values separated by spaces.
-EXPECT <buffer_name> IDX <x> <y> TOLERANCE \
+EXPECT <buffer_name> IDX <x> TOLERANCE \
<tolerance>{1,4} <comparator> <value>+
# Checks that |buffer_name| at |x|, |y| for |width|x|height| pixels has the
diff --git a/src/amber.cc b/src/amber.cc
index 1227c81..2b9e496 100644
--- a/src/amber.cc
+++ b/src/amber.cc
@@ -175,6 +175,12 @@ amber::Result Amber::ExecuteWithShaderData(const amber::Recipe* recipe,
// Hold the executor result until the extractions are complete. This will let
// us dump any buffers requested even on failure.
+ if (script->GetPipelines().empty()) {
+ if (!executor_result.IsSuccess())
+ return executor_result;
+ return {};
+ }
+
// TODO(dsinclair): Figure out how extractions work with multiple pipelines.
auto* pipeline = script->GetPipelines()[0].get();
diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc
index f0573fe..0d45040 100644
--- a/src/amberscript/parser.cc
+++ b/src/amberscript/parser.cc
@@ -27,6 +27,30 @@
namespace amber {
namespace amberscript {
+namespace {
+
+bool IsComparator(const std::string& in) {
+ return in == "EQ" || in == "NE" || in == "GT" || in == "LT" || in == "GE" ||
+ in == "LE";
+}
+
+ProbeSSBOCommand::Comparator ToComparator(const std::string& in) {
+ if (in == "EQ")
+ return ProbeSSBOCommand::Comparator::kEqual;
+ if (in == "NE")
+ return ProbeSSBOCommand::Comparator::kNotEqual;
+ if (in == "GT")
+ return ProbeSSBOCommand::Comparator::kGreater;
+ if (in == "LT")
+ return ProbeSSBOCommand::Comparator::kLess;
+ if (in == "GE")
+ return ProbeSSBOCommand::Comparator::kGreaterOrEqual;
+
+ assert(in == "LE");
+ return ProbeSSBOCommand::Comparator::kLessOrEqual;
+}
+
+} // namespace
Parser::Parser() : amber::Parser() {}
@@ -995,6 +1019,41 @@ Result Parser::ParseClear() {
return ValidateEndOfStatement("CLEAR command");
}
+Result Parser::ParseValues(const std::string& name,
+ const DatumType& type,
+ std::vector<Value>* values) {
+ assert(values);
+
+ auto token = tokenizer_->NextToken();
+ while (!token->IsEOL() && !token->IsEOS()) {
+ Value v;
+
+ if ((type.IsFloat() || type.IsDouble())) {
+ if (!token->IsInteger() && !token->IsDouble()) {
+ return Result(std::string("Invalid value provided to ") + name +
+ " command: " + token->ToOriginalString());
+ }
+
+ Result r = token->ConvertToDouble();
+ if (!r.IsSuccess())
+ return r;
+
+ v.SetDoubleValue(token->AsDouble());
+ } else {
+ if (!token->IsInteger()) {
+ return Result(std::string("Invalid value provided to ") + name +
+ " command: " + token->ToOriginalString());
+ }
+
+ v.SetIntValue(token->AsUint64());
+ }
+
+ values->push_back(v);
+ token = tokenizer_->NextToken();
+ }
+ return {};
+}
+
Result Parser::ParseExpect() {
auto token = tokenizer_->NextToken();
if (!token->IsString())
@@ -1014,16 +1073,24 @@ Result Parser::ParseExpect() {
token->ConvertToDouble();
float x = token->AsFloat();
+ bool has_y_val = false;
+ float y = 0;
token = tokenizer_->NextToken();
- if (!token->IsInteger() || token->AsInt32() < 0)
- return Result("invalid Y value in EXPECT command");
- token->ConvertToDouble();
- float y = token->AsFloat();
+ if (token->IsInteger()) {
+ has_y_val = true;
- // TODO(dsinclair): Handle comparator && TOLERANCE
+ if (token->AsInt32() < 0)
+ return Result("invalid Y value in EXPECT command");
+ token->ConvertToDouble();
+ y = token->AsFloat();
+
+ token = tokenizer_->NextToken();
+ }
- token = tokenizer_->NextToken();
if (token->IsString() && token->AsString() == "SIZE") {
+ if (!has_y_val)
+ return Result("invalid Y value in EXPECT command");
+
auto probe = MakeUnique<ProbeCommand>(buffer);
probe->SetX(x);
probe->SetY(y);
@@ -1081,6 +1148,28 @@ Result Parser::ParseExpect() {
}
script_->AddCommand(std::move(probe));
+ } else if (token->IsString() && IsComparator(token->AsString())) {
+ if (has_y_val)
+ return Result("Y value not needed for non-color comparator");
+ if (!buffer->IsDataBuffer())
+ return Result("comparator must be provided a data buffer");
+
+ auto probe = MakeUnique<ProbeSSBOCommand>(buffer);
+ probe->SetComparator(ToComparator(token->AsString()));
+ probe->SetDatumType(buffer->AsDataBuffer()->GetDatumType());
+ probe->SetOffset(static_cast<uint32_t>(x));
+
+ std::vector<Value> values;
+ Result r =
+ ParseValues("EXPECT", buffer->AsDataBuffer()->GetDatumType(), &values);
+ if (!r.IsSuccess())
+ return r;
+
+ if (values.empty())
+ return Result("missing comparison values for EXPECT command");
+ probe->SetValues(std::move(values));
+ script_->AddCommand(std::move(probe));
+ return {};
} else {
return Result("unexpected token in EXPECT command: " +
token->ToOriginalString());
diff --git a/src/amberscript/parser.h b/src/amberscript/parser.h
index 49aefd2..14f38bc 100644
--- a/src/amberscript/parser.h
+++ b/src/amberscript/parser.h
@@ -18,6 +18,7 @@
#include <memory>
#include <string>
#include <utility>
+#include <vector>
#include "amber/result.h"
#include "src/parser.h"
@@ -64,6 +65,14 @@ class Parser : public amber::Parser {
Result ParseClear();
Result ParseExpect();
+ // Parses a set of values out of the token stream. |name| is the name of the
+ // current command we're parsing for error purposes. The |type| is the type
+ // of data we expect for the current buffer. |values| will be appended to with
+ // the parsed values.
+ Result ParseValues(const std::string& name,
+ const DatumType& type,
+ std::vector<Value>* values);
+
std::unique_ptr<Tokenizer> tokenizer_;
};
diff --git a/src/amberscript/parser_test.cc b/src/amberscript/parser_test.cc
index 441071c..5c7fc7f 100644
--- a/src/amberscript/parser_test.cc
+++ b/src/amberscript/parser_test.cc
@@ -3733,7 +3733,7 @@ EXPECT my_fb IDX 0 INVALID SIZE 250 250 EQ_RGB 0 128 255)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
- EXPECT_EQ("15: invalid Y value in EXPECT command", r.Error());
+ EXPECT_EQ("15: unexpected token in EXPECT command: INVALID", r.Error());
}
TEST_F(AmberScriptParserTest, ExpectRGBMissingSize) {
@@ -4104,5 +4104,65 @@ EXPECT my_fb IDX 0 0 SIZE 250 250 EQ_RGBA 0 128 255 99 EXTRA)";
EXPECT_EQ("15: extra parameters after EXPECT command", r.Error());
}
+TEST_F(AmberScriptParserTest, ExpectEQ) {
+ std::string in = R"(
+BUFFER orig_buf DATA_TYPE int32 SIZE 100 FILL 11
+EXPECT orig_buf IDX 5 EQ 11)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_TRUE(r.IsSuccess()) << r.Error();
+
+ auto script = parser.GetScript();
+ const auto& commands = script->GetCommands();
+ ASSERT_EQ(1U, commands.size());
+
+ auto* cmd = commands[0].get();
+ ASSERT_TRUE(cmd->IsProbeSSBO());
+
+ auto* probe = cmd->AsProbeSSBO();
+ EXPECT_EQ(ProbeSSBOCommand::Comparator::kEqual, probe->GetComparator());
+ EXPECT_EQ(5U, probe->GetOffset());
+ EXPECT_TRUE(probe->GetDatumType().IsInt32());
+ ASSERT_EQ(1U, probe->GetValues().size());
+ EXPECT_EQ(11U, probe->GetValues()[0].AsInt32());
+}
+
+TEST_F(AmberScriptParserTest, ExpectEqMissingValue) {
+ std::string in = R"(
+BUFFER orig_buf DATA_TYPE int32 SIZE 100 FILL 11
+EXPECT orig_buf IDX 5 EQ)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("3: missing comparison values for EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectEQExtraParams) {
+ std::string in = R"(
+BUFFER orig_buf DATA_TYPE int32 SIZE 100 FILL 11
+EXPECT orig_buf IDX 5 EQ 11 EXTRA)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("3: Invalid value provided to EXPECT command: EXTRA", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, MultipleExpect) {
+ std::string in = R"(
+BUFFER orig_buf DATA_TYPE int32 SIZE 100 FILL 11
+BUFFER dest_buf DATA_TYPE int32 SIZE 100 FILL 22
+
+EXPECT orig_buf IDX 0 EQ 11
+EXPECT dest_buf IDX 0 EQ 22
+)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_TRUE(r.IsSuccess()) << r.Error();
+}
+
} // namespace amberscript
} // namespace amber
diff --git a/src/executor.cc b/src/executor.cc
index eda60f0..8bcc315 100644
--- a/src/executor.cc
+++ b/src/executor.cc
@@ -53,17 +53,16 @@ Result Executor::Execute(Engine* engine,
ExecutionType executionType) {
engine->SetEngineData(script->GetEngineData());
- if (script->GetPipelines().empty())
- return Result("no pipelines defined");
-
- Result r = CompileShaders(script, shader_map);
- if (!r.IsSuccess())
- return r;
-
- for (auto& pipeline : script->GetPipelines()) {
- r = engine->CreatePipeline(pipeline.get());
+ if (!script->GetPipelines().empty()) {
+ Result r = CompileShaders(script, shader_map);
if (!r.IsSuccess())
return r;
+
+ for (auto& pipeline : script->GetPipelines()) {
+ r = engine->CreatePipeline(pipeline.get());
+ if (!r.IsSuccess())
+ return r;
+ }
}
if (executionType == ExecutionType::kPipelineCreateOnly)
@@ -71,6 +70,7 @@ Result Executor::Execute(Engine* engine,
// Process Commands
for (const auto& cmd : script->GetCommands()) {
+ Result r;
if (cmd->IsProbe()) {
assert(cmd->AsProbe()->GetBuffer()->IsFormatBuffer());
diff --git a/tests/cases/expect_eq.amber b/tests/cases/expect_eq.amber
new file mode 100644
index 0000000..f9affc6
--- /dev/null
+++ b/tests/cases/expect_eq.amber
@@ -0,0 +1,17 @@
+#!amber
+# Copyright 2019 The Amber Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+BUFFER orig_buf DATA_TYPE int32 SIZE 100 FILL 11
+EXPECT orig_buf IDX 0 EQ 11