blob: 6ab92be7595c7e8855be3bb9e178759fb1030cd2 [file] [log] [blame]
// 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
//
// http://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 parseried.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "gtest/gtest.h"
#include "src/amberscript/parser.h"
namespace amber {
namespace amberscript {
using AmberScriptParserTest = testing::Test;
TEST_F(AmberScriptParserTest, PipelineWithUnknownShader) {
std::string in = R"(
PIPELINE graphics my_pipeline
ATTACH my_shader
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("3: unknown shader in ATTACH command", r.Error());
}
TEST_F(AmberScriptParserTest, DuplicateShadersInAPipeline) {
std::string in = R"(
SHADER vertex my_shader PASSTHROUGH
PIPELINE graphics my_pipeline
ATTACH my_shader
ATTACH my_shader
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("6: can not add duplicate shader to pipeline", r.Error());
}
TEST_F(AmberScriptParserTest, AttachInvalidToken) {
std::string in = R"(PIPELINE graphics my_pipeline
ATTACH 1234
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("2: invalid token in ATTACH command", r.Error());
}
TEST_F(AmberScriptParserTest, AttachExtraParameter) {
std::string in = R"(
SHADER vertex my_shader PASSTHROUGH
PIPELINE graphics my_pipeline
ATTACH my_shader INVALID
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("4: unknown ATTACH parameter: INVALID", r.Error());
}
TEST_F(AmberScriptParserTest, AttachMissingValue) {
std::string in = R"(
SHADER vertex my_shader PASSTHROUGH
PIPELINE graphics my_pipeline
ATTACH
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("5: invalid token in ATTACH command", r.Error());
}
TEST_F(AmberScriptParserTest, ComputeShaderInGraphicsPipeline) {
std::string in = R"(SHADER compute my_shader GLSL
void main() {
gl_FragColor = vec3(2, 3, 4);
}
END
PIPELINE graphics my_pipeline
ATTACH my_shader
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess()) << r.Error();
EXPECT_EQ("9: can not add a compute shader to a graphics pipeline",
r.Error());
}
struct ShaderTypeData {
const char* name;
ShaderType type;
};
using AmberScriptParserPipelineAttachTest =
testing::TestWithParam<ShaderTypeData>;
TEST_P(AmberScriptParserPipelineAttachTest, GraphicsShaderInComputePipeline) {
auto test_data = GetParam();
std::string in = "SHADER " + std::string(test_data.name) + R"( my_shader GLSL
void main() {
gl_FragColor = vec3(2, 3, 4);
}
END
PIPELINE compute my_pipeline
ATTACH my_shader
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess()) << r.Error();
EXPECT_EQ("9: only compute shaders allowed in a compute pipeline", r.Error());
}
INSTANTIATE_TEST_SUITE_P(
AmberScriptParserPipelineAttachTests,
AmberScriptParserPipelineAttachTest,
testing::Values(
ShaderTypeData{"vertex", kShaderTypeVertex},
ShaderTypeData{"fragment", kShaderTypeFragment},
ShaderTypeData{"geometry", kShaderTypeGeometry},
ShaderTypeData{"tessellation_evaluation",
kShaderTypeTessellationEvaluation},
ShaderTypeData{
"tessellation_control",
kShaderTypeTessellationControl})); // NOLINT(whitespace/parens)
TEST_F(AmberScriptParserTest, PipelineEntryPoint) {
std::string in = R"(
SHADER vertex my_shader PASSTHROUGH
SHADER fragment my_fragment GLSL
# GLSL Shader
END
PIPELINE graphics my_pipeline
ATTACH my_shader ENTRY_POINT green
ATTACH my_fragment
END
)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
auto script = parser.GetScript();
const auto& pipelines = script->GetPipelines();
ASSERT_EQ(1U, pipelines.size());
const auto* pipeline = pipelines[0].get();
const auto& shaders = pipeline->GetShaders();
ASSERT_EQ(2U, shaders.size());
ASSERT_TRUE(shaders[0].GetShader() != nullptr);
EXPECT_EQ(kShaderTypeVertex, shaders[0].GetShader()->GetType());
EXPECT_EQ("green", shaders[0].GetEntryPoint());
ASSERT_TRUE(shaders[1].GetShader() != nullptr);
EXPECT_EQ(kShaderTypeFragment, shaders[1].GetShader()->GetType());
EXPECT_EQ("main", shaders[1].GetEntryPoint());
}
TEST_F(AmberScriptParserTest, PipelineEntryPointWithInvalidValue) {
std::string in = R"(
SHADER compute my_compute GLSL
# Compute Shader
END
PIPELINE compute my_pipeline
ATTACH my_compute ENTRY_POINT 1234
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("6: missing shader name in ATTACH ENTRY_POINT command", r.Error());
}
TEST_F(AmberScriptParserTest, PipelineEntryPointMissingValue) {
std::string in = R"(
SHADER compute my_compute GLSL
# Compute Shader
END
PIPELINE compute my_pipeline
ATTACH my_compute ENTRY_POINT
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: missing shader name in ATTACH ENTRY_POINT command", r.Error());
}
TEST_F(AmberScriptParserTest, PipelineEntryPointExtraParameter) {
std::string in = R"(
SHADER compute my_compute GLSL
# Compute Shader
END
PIPELINE compute my_pipeline
ATTACH my_compute ENTRY_POINT green INVALID
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("6: unknown ATTACH parameter: INVALID", r.Error());
}
TEST_F(AmberScriptParserTest, PiplineMultiShaderAttach) {
std::string in = R"(
SHADER multi my_shader GLSL
# shaders
END
PIPELINE compute my_pipeline
ATTACH my_shader TYPE compute ENTRY_POINT my_entry_point
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
auto script = parser.GetScript();
const auto& pipelines = script->GetPipelines();
ASSERT_EQ(1U, pipelines.size());
const auto* pipeline = pipelines[0].get();
const auto& shaders = pipeline->GetShaders();
ASSERT_EQ(1U, shaders.size());
ASSERT_TRUE(shaders[0].GetShader() != nullptr);
EXPECT_EQ(kShaderTypeMulti, shaders[0].GetShader()->GetType());
EXPECT_EQ(kShaderTypeCompute, shaders[0].GetShaderType());
EXPECT_EQ("my_entry_point", shaders[0].GetEntryPoint());
}
TEST_F(AmberScriptParserTest,
PipelineMultiShaderMismatchPipelineAndShaderType) {
std::string in = R"(
SHADER multi my_shader GLSL
# shaders
END
PIPELINE graphics my_pipeline
ATTACH my_shader TYPE compute ENTRY_POINT my_entry_point
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("6: can not add a compute shader to a graphics pipeline",
r.Error());
}
TEST_F(AmberScriptParserTest, PipelineMultiShaderMissingEntryPoint) {
std::string in = R"(
SHADER multi my_shader GLSL
# shaders
END
PIPELINE graphics my_pipeline
ATTACH my_shader TYPE fragment
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: ATTACH TYPE requires an ENTRY_POINT", r.Error());
}
TEST_F(AmberScriptParserTest, PipelineMultiShaderMissingType) {
std::string in = R"(
SHADER multi my_shader GLSL
# shaders
END
PIPELINE graphics my_pipeline
ATTACH my_shader
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: multi shader ATTACH requires TYPE", r.Error());
}
TEST_F(AmberScriptParserTest, PipelineMultiShaderMissingTypeWithEntryPoint) {
std::string in = R"(
SHADER multi my_shader GLSL
# shaders
END
PIPELINE graphics my_pipeline
ATTACH my_shader ENTRY_POINT my_ep
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("6: ATTACH missing TYPE for multi shader", r.Error());
}
TEST_F(AmberScriptParserTest, PipelineSpecializationUint32) {
std::string in = R"(
SHADER compute my_shader GLSL
#shaders
END
PIPELINE compute my_pipeline
ATTACH my_shader TYPE compute ENTRY_POINT my_ep SPECIALIZE 1 AS uint32 4
END)";
Parser parser;
Result r = parser.Parse(in);
EXPECT_EQ(r.Error(), "");
ASSERT_TRUE(r.IsSuccess());
auto script = parser.GetScript();
const auto& pipelines = script->GetPipelines();
ASSERT_EQ(1U, pipelines.size());
const auto* pipeline = pipelines[0].get();
const auto& shaders = pipeline->GetShaders();
ASSERT_EQ(1U, shaders.size());
EXPECT_EQ(1u, shaders[0].GetSpecialization().size());
EXPECT_EQ(4u, shaders[0].GetSpecialization().at(1));
}
TEST_F(AmberScriptParserTest, PipelineSpecializationInt32) {
std::string in = R"(
SHADER compute my_shader GLSL
#shaders
END
PIPELINE compute my_pipeline
ATTACH my_shader TYPE compute ENTRY_POINT my_ep SPECIALIZE 2 AS int32 -1
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_TRUE(r.IsSuccess());
auto script = parser.GetScript();
const auto& pipelines = script->GetPipelines();
ASSERT_EQ(1U, pipelines.size());
const auto* pipeline = pipelines[0].get();
const auto& shaders = pipeline->GetShaders();
ASSERT_EQ(1U, shaders.size());
EXPECT_EQ(1u, shaders[0].GetSpecialization().size());
EXPECT_EQ(0xffffffffu, shaders[0].GetSpecialization().at(2));
}
TEST_F(AmberScriptParserTest, PipelineSpecializationFloat) {
std::string in = R"(
SHADER compute my_shader GLSL
#shaders
END
PIPELINE compute my_pipeline
ATTACH my_shader TYPE compute ENTRY_POINT my_ep SPECIALIZE 3 AS float 1.1
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_TRUE(r.IsSuccess());
auto script = parser.GetScript();
const auto& pipelines = script->GetPipelines();
ASSERT_EQ(1U, pipelines.size());
const auto* pipeline = pipelines[0].get();
const auto& shaders = pipeline->GetShaders();
ASSERT_EQ(1U, shaders.size());
EXPECT_EQ(1u, shaders[0].GetSpecialization().size());
EXPECT_EQ(0x3f8ccccdu, shaders[0].GetSpecialization().at(3));
}
TEST_F(AmberScriptParserTest, PipelineSpecializationIDIsString) {
std::string in = R"(
SHADER compute my_shader GLSL
#shaders
END
PIPELINE compute my_pipeline
ATTACH my_shader TYPE compute ENTRY_POINT my_ep SPECIALIZE s3 AS float 1.1
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("6: specialization ID must be an integer", r.Error());
}
TEST_F(AmberScriptParserTest, PipelineSpecializationNoAS) {
std::string in = R"(
SHADER compute my_shader GLSL
#shaders
END
PIPELINE compute my_pipeline
ATTACH my_shader TYPE compute ENTRY_POINT my_ep SPECIALIZE 1 ASa float 1.1
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("6: expected AS as next token", r.Error());
}
TEST_F(AmberScriptParserTest, PipelineSpecializationNotDataType) {
std::string in = R"(
SHADER compute my_shader GLSL
#shaders
END
PIPELINE compute my_pipeline
ATTACH my_shader TYPE compute ENTRY_POINT my_ep SPECIALIZE 1 AS uint 1.1
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("6: invalid data type 'uint' provided", r.Error());
}
TEST_F(AmberScriptParserTest, PipelineSpecializationBadDataType) {
std::string in = R"(
SHADER compute my_shader GLSL
#shaders
END
PIPELINE compute my_pipeline
ATTACH my_shader ENTRY_POINT my_ep SPECIALIZE 1 AS uint8 1.1
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ(
"6: only 32-bit types are currently accepted for specialization values",
r.Error());
}
TEST_F(AmberScriptParserTest, PipelineSpecializationMultipleSpecializations) {
std::string in = R"(
SHADER compute my_shader GLSL
#shaders
END
PIPELINE compute my_pipeline
ATTACH my_shader TYPE compute ENTRY_POINT my_ep \
SPECIALIZE 1 AS uint32 4 \
SPECIALIZE 2 AS uint32 5 \
SPECIALIZE 5 AS uint32 1
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_TRUE(r.IsSuccess());
auto script = parser.GetScript();
const auto& pipelines = script->GetPipelines();
ASSERT_EQ(1U, pipelines.size());
const auto* pipeline = pipelines[0].get();
const auto& shaders = pipeline->GetShaders();
ASSERT_EQ(1U, shaders.size());
EXPECT_EQ(3u, shaders[0].GetSpecialization().size());
EXPECT_EQ(4u, shaders[0].GetSpecialization().at(1));
EXPECT_EQ(5u, shaders[0].GetSpecialization().at(2));
EXPECT_EQ(1u, shaders[0].GetSpecialization().at(5));
}
TEST_F(AmberScriptParserTest, PipelineSpecializationNoType) {
std::string in = R"(
SHADER compute my_shader GLSL
#shaders
END
PIPELINE compute my_pipeline
ATTACH my_shader SPECIALIZE 1 AS uint32 4
END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_TRUE(r.IsSuccess());
auto script = parser.GetScript();
const auto& pipelines = script->GetPipelines();
ASSERT_EQ(1U, pipelines.size());
const auto* pipeline = pipelines[0].get();
const auto& shaders = pipeline->GetShaders();
ASSERT_EQ(1U, shaders.size());
EXPECT_EQ(1u, shaders[0].GetSpecialization().size());
EXPECT_EQ(4u, shaders[0].GetSpecialization().at(1));
}
} // namespace amberscript
} // namespace amber