aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/amber_script.md29
-rw-r--r--src/amberscript/parser.cc134
-rw-r--r--src/amberscript/parser.h1
-rw-r--r--src/amberscript/parser_test.cc706
-rw-r--r--src/vulkan/engine_vulkan.cc3
-rw-r--r--tests/cases/clear.amber39
6 files changed, 896 insertions, 16 deletions
diff --git a/docs/amber_script.md b/docs/amber_script.md
index d1e6ecf..454cfe7 100644
--- a/docs/amber_script.md
+++ b/docs/amber_script.md
@@ -314,19 +314,26 @@ CLEAR <pipeline>
```
# Checks that |buffer_name| at |x|, |y| has the given |value|s when compared
# with the given |comparator|.
-EXPECT <buffer_name> IDX <x> <y> <comparator> <value>+
+EXPECT <pipeline_name> BUFFER <buffer_name> IDX <x> <y> <comparator> <value>+
# Checks that |buffer_name| at |x|, |y| 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 <tolerance>{1,4} <comparator> \
- <value>+
+EXPECT <pipeline_name> BUFFER <buffer_name> IDX <x> <y> TOLERANCE \
+ <tolerance>{1,4} <comparator> <value>+
# Checks that |buffer_name| at |x|, |y| for |width|x|height| pixels has the
# given |r|, |g|, |b| values. Each r, g, b value is an integer from 0-255.
-EXPECT <buffer_name> IDX <x_in_pixels> <y_in_pixels> \
+EXPECT <pipeline_name> BUFFER <buffer_name> IDX <x_in_pixels> <y_in_pixels> \
 SIZE <width_in_pixels> <height_in_pixels> \
 EQ_RGB <r (0 - 255)> <g (0 - 255)> <b (0 - 255)>
+
+# Checks that |buffer_name| at |x|, |y| for |width|x|height| pixels has the
+# given |r|, |g|, |b|, |a| values. Each r, g, b, a value is an integer
+# from 0-255.
+EXPECT <pipeline_name> BUFFER <buffer_name> IDX <x_in_pixels> <y_in_pixels> \
+  SIZE <width_in_pixels> <height_in_pixels> \
+  EQ_RGBA <r (0 - 255)> <g (0 - 255)> <b (0 - 255)> <a (0 - 255)>
```
## Examples
@@ -359,13 +366,13 @@ END  # pipeline
RUN kComputePipeline 256 256 1
# Four corners
-EXPECT kComputeBuffer IDX 0 EQ 0 0
-EXPECT kComputeBuffer IDX 2040 EQ 255 0
-EXPECT kComputeBuffer IDX 522240 EQ 0 255
-EXPECT kComputeBuffer IDX 524280 EQ 255 255
+EXPECT kComputePipeline BUFFER kComputeBuffer IDX 0 EQ 0 0
+EXPECT kComputePipeline BUFFER kComputeBuffer IDX 2040 EQ 255 0
+EXPECT kComputePipeline BUFFER kComputeBuffer IDX 522240 EQ 0 255
+EXPECT kComputePipeline BUFFER kComputeBuffer IDX 524280 EQ 255 255
# Center
-EXPECT kComputeBuffer IDX 263168 EQ 128 128
+EXPECT kComputePipeline BUFFER kComputeBuffer IDX 263168 EQ 128 128
```
### Entry Points
@@ -440,8 +447,8 @@ END  # pipeline
RUN kRedPipeline DRAW_RECT POS 0 0 SIZE 256 256
RUN kGreenPipeline DRAW_RECT POS 128 128 SIZE 256 256
-EXPECT kImgBuffer IDX 0 0 SIZE 127 127 EQ_RGB 255 0 0
-EXPECT kImgBuffer IDX 128 128 SIZE 128 128 EQ_RGB 0 255 0
+EXPECT kGreenPipeline BUFFER kImgBuffer IDX 0 0 SIZE 127 127 EQ_RGB 255 0 0
+EXPECT kGreenPipeline BUFFER kImgBuffer IDX 128 128 SIZE 128 128 EQ_RGB 0 255 0
```
### Buffers
diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc
index a810457..9b99f91 100644
--- a/src/amberscript/parser.cc
+++ b/src/amberscript/parser.cc
@@ -50,14 +50,16 @@ Result Parser::Parse(const std::string& data) {
std::string tok = token->AsString();
if (tok == "BUFFER") {
r = ParseBuffer();
+ } else if (tok == "CLEAR") {
+ r = ParseClear();
+ } else if (tok == "EXPECT") {
+ r = ParseExpect();
} else if (tok == "PIPELINE") {
r = ParsePipelineBlock();
- } else if (tok == "SHADER") {
- r = ParseShaderBlock();
} else if (tok == "RUN") {
r = ParseRun();
- } else if (tok == "CLEAR") {
- r = ParseClear();
+ } else if (tok == "SHADER") {
+ r = ParseShaderBlock();
} else {
r = Result("unknown token: " + tok);
}
@@ -548,6 +550,8 @@ Result Parser::ParsePipelineBind(Pipeline* pipeline) {
if (!token->IsInteger())
return Result("invalid value for BIND LOCATION");
+ buffer->SetBufferType(BufferType::kColor);
+
Result r = pipeline->AddColorAttachment(buffer, token->AsUint32());
if (!r.IsSuccess())
return r;
@@ -989,5 +993,127 @@ Result Parser::ParseClear() {
return ValidateEndOfStatement("CLEAR command");
}
+Result Parser::ParseExpect() {
+ auto token = tokenizer_->NextToken();
+ if (token->IsEOS() || token->IsEOL())
+ return Result("missing pipeline name in EXPECT command");
+ if (!token->IsString())
+ return Result("invalid pipeline name in EXPECT command");
+
+ auto* pipeline = script_->GetPipeline(token->AsString());
+ if (!pipeline)
+ return Result("unknown pipeline name for EXPECT command");
+
+ token = tokenizer_->NextToken();
+ if (token->IsEOS() || token->IsEOL())
+ return Result("missing BUFFER in EXPECT command");
+ if (!token->IsString() || token->AsString() != "BUFFER") {
+ return Result("expected BUFFER got '" + token->ToOriginalString() +
+ "' in " + "EXPECT command");
+ }
+
+ token = tokenizer_->NextToken();
+ if (!token->IsString())
+ return Result("invalid buffer name in EXPECT command");
+
+ auto* buffer = script_->GetBuffer(token->AsString());
+ if (!buffer)
+ return Result("unknown buffer name for EXPECT command");
+
+ token = tokenizer_->NextToken();
+ if (!token->IsString() || token->AsString() != "IDX")
+ return Result("missing IDX in EXPECT command");
+
+ token = tokenizer_->NextToken();
+ if (!token->IsInteger() || token->AsInt32() < 0)
+ return Result("invalid X value in EXPECT command");
+ token->ConvertToDouble();
+ float x = token->AsFloat();
+
+ token = tokenizer_->NextToken();
+ if (!token->IsInteger() || token->AsInt32() < 0)
+ return Result("invalid Y value in EXPECT command");
+ token->ConvertToDouble();
+ float y = token->AsFloat();
+
+ // TODO(dsinclair): Handle comparator && TOLERANCE
+
+ token = tokenizer_->NextToken();
+ if (token->IsString() && token->AsString() == "SIZE") {
+ bool found = false;
+ for (const auto& info : pipeline->GetColorAttachments()) {
+ if (info.buffer == buffer) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return Result("buffer not in pipeline for EXPECT command");
+
+ auto probe = MakeUnique<ProbeCommand>(pipeline, buffer);
+ probe->SetX(x);
+ probe->SetY(y);
+ probe->SetProbeRect();
+
+ token = tokenizer_->NextToken();
+ if (!token->IsInteger() || token->AsInt32() <= 0)
+ return Result("invalid width in EXPECT command");
+ token->ConvertToDouble();
+ probe->SetWidth(token->AsFloat());
+
+ token = tokenizer_->NextToken();
+ if (!token->IsInteger() || token->AsInt32() <= 0)
+ return Result("invalid height in EXPECT command");
+ token->ConvertToDouble();
+ probe->SetHeight(token->AsFloat());
+
+ token = tokenizer_->NextToken();
+ if (!token->IsString()) {
+ return Result("invalid token in EXPECT command:" +
+ token->ToOriginalString());
+ }
+
+ if (token->AsString() == "EQ_RGBA") {
+ probe->SetIsRGBA();
+ } else if (token->AsString() != "EQ_RGB") {
+ return Result("unknown comparator type in EXPECT: " +
+ token->ToOriginalString());
+ }
+
+ token = tokenizer_->NextToken();
+ if (!token->IsInteger() || token->AsInt32() < 0 || token->AsInt32() > 255)
+ return Result("invalid R value in EXPECT command");
+ token->ConvertToDouble();
+ probe->SetR(token->AsFloat());
+
+ token = tokenizer_->NextToken();
+ if (!token->IsInteger() || token->AsInt32() < 0 || token->AsInt32() > 255)
+ return Result("invalid G value in EXPECT command");
+ token->ConvertToDouble();
+ probe->SetG(token->AsFloat());
+
+ token = tokenizer_->NextToken();
+ if (!token->IsInteger() || token->AsInt32() < 0 || token->AsInt32() > 255)
+ return Result("invalid B value in EXPECT command");
+ token->ConvertToDouble();
+ probe->SetB(token->AsFloat());
+
+ if (probe->IsRGBA()) {
+ token = tokenizer_->NextToken();
+ if (!token->IsInteger() || token->AsInt32() < 0 || token->AsInt32() > 255)
+ return Result("invalid A value in EXPECT command");
+ token->ConvertToDouble();
+ probe->SetA(token->AsFloat());
+ }
+
+ script_->AddCommand(std::move(probe));
+ } else {
+ return Result("unexpected token in EXPECT command: " +
+ token->ToOriginalString());
+ }
+
+ return ValidateEndOfStatement("EXPECT command");
+}
+
} // namespace amberscript
} // namespace amber
diff --git a/src/amberscript/parser.h b/src/amberscript/parser.h
index 60b32a0..49aefd2 100644
--- a/src/amberscript/parser.h
+++ b/src/amberscript/parser.h
@@ -62,6 +62,7 @@ class Parser : public amber::Parser {
Result ParsePipelineIndexData(Pipeline*);
Result ParseRun();
Result ParseClear();
+ Result ParseExpect();
std::unique_ptr<Tokenizer> tokenizer_;
};
diff --git a/src/amberscript/parser_test.cc b/src/amberscript/parser_test.cc
index e300614..d89c188 100644
--- a/src/amberscript/parser_test.cc
+++ b/src/amberscript/parser_test.cc
@@ -3502,5 +3502,711 @@ CLEAR my_pipeline EXTRA)";
EXPECT_EQ("12: extra parameters after CLEAR command", r.Error());
}
+TEST_F(AmberScriptParserTest, ExpectRGB) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 5 6 SIZE 250 150 EQ_RGB 2 128 255)";
+
+ 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->IsProbe());
+
+ auto* probe = cmd->AsProbe();
+ EXPECT_FALSE(probe->IsRGBA());
+ EXPECT_TRUE(probe->IsProbeRect());
+ EXPECT_FALSE(probe->IsRelative());
+ EXPECT_FALSE(probe->IsWholeWindow());
+ EXPECT_EQ(5U, probe->GetX());
+ EXPECT_EQ(6U, probe->GetY());
+ EXPECT_EQ(250U, probe->GetWidth());
+ EXPECT_EQ(150U, probe->GetHeight());
+ EXPECT_EQ(2U, probe->GetR());
+ EXPECT_EQ(128U, probe->GetG());
+ EXPECT_EQ(255U, probe->GetB());
+}
+
+TEST_F(AmberScriptParserTest, ExpectRGBA) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 2 7 SIZE 20 88 EQ_RGBA 2 128 255 99)";
+
+ 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->IsProbe());
+
+ auto* probe = cmd->AsProbe();
+ EXPECT_TRUE(probe->IsRGBA());
+ EXPECT_TRUE(probe->IsProbeRect());
+ EXPECT_FALSE(probe->IsRelative());
+ EXPECT_FALSE(probe->IsWholeWindow());
+ EXPECT_EQ(2U, probe->GetX());
+ EXPECT_EQ(7U, probe->GetY());
+ EXPECT_EQ(20U, probe->GetWidth());
+ EXPECT_EQ(88U, probe->GetHeight());
+ EXPECT_EQ(2U, probe->GetR());
+ EXPECT_EQ(128U, probe->GetG());
+ EXPECT_EQ(255U, probe->GetB());
+ EXPECT_EQ(99U, probe->GetA());
+}
+
+TEST_F(AmberScriptParserTest, ExpectMissingPipelineName) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT BUFFER my_fb IDX 0 0 SIZE 250 250 EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: unknown pipeline name for EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectInvalidPipelineName) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT unknown_pipeline BUFFER my_fb IDX 0 0 SIZE 250 250 EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: unknown pipeline name for EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectMissingBuffer) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline my_fb IDX 0 0 SIZE 250 250 EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: expected BUFFER got 'my_fb' in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectMissingBufferName) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER IDX 0 0 SIZE 250 250 EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: unknown buffer name for EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectInvalidBufferName) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER unknown_buffer IDX 0 0 SIZE 250 250 EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: unknown buffer name for EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectBufferNotInPipeline) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER other_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+END
+
+EXPECT my_pipeline BUFFER other_fb IDX 0 0 SIZE 250 250 EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("13: buffer not in pipeline for EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectMissingIDX) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb 0 0 SIZE 250 250 EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: missing IDX in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectMissingIDXValues) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX SIZE 250 250 EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: invalid X value in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectMissingIdxY) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 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());
+}
+
+TEST_F(AmberScriptParserTest, ExpectIdxInvalidX) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX INVAILD 0 SIZE 250 250 EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: invalid X value in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectIdxInvalidY) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER 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());
+}
+
+TEST_F(AmberScriptParserTest, ExpectRGBMissingSize) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 250 250 EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: unexpected token in EXPECT command: 250", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectSizeMissingValues) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: invalid width in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectSizeMissingHeight) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE 250 EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: invalid height in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectSizeInvalidWidth) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE INVALID 250 EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: invalid width in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectSizeInvalidHeight) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE 250 INVALID EQ_RGB 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: invalid height in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectSizeInvalidComparitor) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE 250 250 INVALID 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: unknown comparator type in EXPECT: INVALID", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectRGBMissingValues) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE 250 250 EQ_RGB)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: invalid R value in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectRGBMissingB) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE 250 250 EQ_RGB 0 128)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: invalid B value in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectRGBMissingG) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE 250 250 EQ_RGB 0)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: invalid G value in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectRGBAMissingA) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE 250 250 EQ_RGBA 0 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: invalid A value in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectRGBInvalidR) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE 250 250 EQ_RGB INVALID 128 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: invalid R value in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectRGBInvalidG) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE 250 250 EQ_RGB 0 INVALID 255)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: invalid G value in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectRGBInvalidB) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE 250 250 EQ_RGB 0 128 INVALID)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: invalid B value in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectRGBAInvalidA) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE 250 250 \
+ EQ_RGBA 0 128 255 INVALID)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("16: invalid A value in EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectRGBExtraParam) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE 250 250 EQ_RGB 0 128 255 EXTRA)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("15: extra parameters after EXPECT command", r.Error());
+}
+
+TEST_F(AmberScriptParserTest, ExpectRGBAExtraParam) {
+ std::string in = R"(
+SHADER vertex my_shader PASSTHROUGH
+SHADER fragment my_fragment GLSL
+# GLSL Shader
+END
+BUFFER my_fb FORMAT R32G32B32A32_SFLOAT
+
+PIPELINE graphics my_pipeline
+ ATTACH my_shader
+ ATTACH my_fragment
+
+ BIND BUFFER my_fb AS color LOCATION 0
+END
+
+EXPECT my_pipeline BUFFER my_fb IDX 0 0 SIZE 250 250 \
+ EQ_RGBA 0 128 255 99 EXTRA)";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+ EXPECT_EQ("16: extra parameters after EXPECT command", r.Error());
+}
+
} // namespace amberscript
} // namespace amber
diff --git a/src/vulkan/engine_vulkan.cc b/src/vulkan/engine_vulkan.cc
index 01f040b..56cb652 100644
--- a/src/vulkan/engine_vulkan.cc
+++ b/src/vulkan/engine_vulkan.cc
@@ -137,7 +137,8 @@ Result EngineVulkan::Shutdown() {
nullptr);
}
- info.vk_pipeline->Shutdown();
+ if (info.vk_pipeline != VK_NULL_HANDLE)
+ info.vk_pipeline->Shutdown();
}
pool_ = nullptr;
diff --git a/tests/cases/clear.amber b/tests/cases/clear.amber
new file mode 100644
index 0000000..705b290
--- /dev/null
+++ b/tests/cases/clear.amber
@@ -0,0 +1,39 @@
+#!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.
+
+SHADER vertex vtex_shader PASSTHROUGH
+SHADER fragment frag_shader GLSL
+#version 430
+
+layout(location = 0) in vec4 color_in;
+layout(location = 0) out vec4 color_out;
+
+void main() {
+ color_out = color_in;
+}
+END
+
+BUFFER img_buf FORMAT B8G8R8A8_UNORM
+
+PIPELINE graphics my_pipeline
+ ATTACH vtex_shader
+ ATTACH frag_shader
+
+ FRAMEBUFFER_SIZE 256 256
+ BIND BUFFER img_buf AS color LOCATION 0
+END
+
+CLEAR my_pipeline
+EXPECT my_pipeline BUFFER img_buf IDX 0 0 SIZE 256 256 EQ_RGBA 0 0 0 0