blob: 4d6f3660b7c15089d6812829a57b879c3bff6cd7 [file] [log] [blame]
// Copyright 2018 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 implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/amberscript/pipeline.h"
#include "gtest/gtest.h"
namespace amber {
namespace amberscript {
namespace {
struct ShaderTypeData {
ShaderType type;
};
} // namespace
using AmberScriptPipelineTest = testing::Test;
TEST_F(AmberScriptPipelineTest, AddShader) {
Shader v(ShaderType::kVertex);
Shader f(ShaderType::kFragment);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&v);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&f);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
const auto& shaders = p.GetShaders();
EXPECT_EQ(2U, shaders.size());
EXPECT_EQ(&v, shaders[0].GetShader());
EXPECT_EQ(&f, shaders[1].GetShader());
}
TEST_F(AmberScriptPipelineTest, MissingShader) {
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(nullptr);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("shader can not be null when attached to pipeline", r.Error());
}
TEST_F(AmberScriptPipelineTest, DuplicateShaders) {
Shader v(ShaderType::kVertex);
Shader f(ShaderType::kFragment);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&v);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&f);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&v);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("can not add duplicate shader to pipeline", r.Error());
}
TEST_F(AmberScriptPipelineTest, DuplicateShaderType) {
Shader v(ShaderType::kVertex);
Shader f(ShaderType::kVertex);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&v);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&f);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("can not add duplicate shader type to pipeline", r.Error());
}
using AmberScriptPipelineComputePipelineTest =
testing::TestWithParam<ShaderTypeData>;
TEST_P(AmberScriptPipelineComputePipelineTest,
SettingGraphicsShaderToComputePipeline) {
const auto test_data = GetParam();
Shader s(test_data.type);
Pipeline p(PipelineType::kCompute);
Result r = p.AddShader(&s);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("only compute shaders allowed in a compute pipeline", r.Error());
}
INSTANTIATE_TEST_CASE_P(
AmberScriptPipelineComputePipelineTests,
AmberScriptPipelineComputePipelineTest,
testing::Values(ShaderTypeData{ShaderType::kVertex},
ShaderTypeData{ShaderType::kFragment},
ShaderTypeData{ShaderType::kGeometry},
ShaderTypeData{ShaderType::kTessellationEvaluation},
ShaderTypeData{ShaderType::kTessellationControl}), );
TEST_F(AmberScriptPipelineTest, SettingComputeShaderToGraphicsPipeline) {
Shader c(ShaderType::kCompute);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&c);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("can not add a compute shader to a graphics pipeline", r.Error());
}
TEST_F(AmberScriptPipelineTest, SetShaderOptimizations) {
Shader v(ShaderType::kVertex);
Shader f(ShaderType::kFragment);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&v);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&f);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
std::vector<std::string> first = {"First", "Second"};
std::vector<std::string> second = {"Third", "Forth"};
r = p.SetShaderOptimizations(&f, first);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.SetShaderOptimizations(&v, second);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
const auto& shaders = p.GetShaders();
EXPECT_EQ(2U, shaders.size());
EXPECT_EQ(second, shaders[0].GetShaderOptimizations());
EXPECT_EQ(first, shaders[1].GetShaderOptimizations());
}
TEST_F(AmberScriptPipelineTest, DuplicateShaderOptimizations) {
Shader v(ShaderType::kVertex);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&v);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
std::vector<std::string> data = {"One", "One"};
r = p.SetShaderOptimizations(&v, data);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("duplicate optimization flag (One) set on shader", r.Error());
}
TEST_F(AmberScriptPipelineTest, SetOptimizationForMissingShader) {
Pipeline p(PipelineType::kGraphics);
Result r = p.SetShaderOptimizations(nullptr, {"One", "Two"});
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("invalid shader specified for optimizations", r.Error());
}
TEST_F(AmberScriptPipelineTest, SetOptimizationForInvalidShader) {
Shader v(ShaderType::kVertex);
v.SetName("my_shader");
Pipeline p(PipelineType::kGraphics);
Result r = p.SetShaderOptimizations(&v, {"One", "Two"});
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("unknown shader specified for optimizations: my_shader", r.Error());
}
TEST_F(AmberScriptPipelineTest,
GraphicsPipelineRequiresVertexAndFragmentShader) {
Shader v(ShaderType::kVertex);
Shader f(ShaderType::kFragment);
Shader g(ShaderType::kGeometry);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&v);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&g);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&f);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.Validate();
EXPECT_TRUE(r.IsSuccess()) << r.Error();
}
TEST_F(AmberScriptPipelineTest, GraphicsPipelineMissingFragmentShader) {
Shader v(ShaderType::kVertex);
Shader g(ShaderType::kGeometry);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&v);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&g);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.Validate();
EXPECT_FALSE(r.IsSuccess()) << r.Error();
EXPECT_EQ("graphics pipeline requires a fragment shader", r.Error());
}
TEST_F(AmberScriptPipelineTest, GraphicsPipelineMissingVertexShader) {
Shader f(ShaderType::kFragment);
Shader g(ShaderType::kGeometry);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&g);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&f);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.Validate();
EXPECT_FALSE(r.IsSuccess()) << r.Error();
EXPECT_EQ("graphics pipeline requires a vertex shader", r.Error());
}
TEST_F(AmberScriptPipelineTest,
GraphicsPipelineMissingVertexAndFragmentShader) {
Shader g(ShaderType::kGeometry);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&g);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.Validate();
EXPECT_FALSE(r.IsSuccess()) << r.Error();
EXPECT_EQ("graphics pipeline requires vertex and fragment shaders",
r.Error());
}
TEST_F(AmberScriptPipelineTest, GraphicsPipelineWihoutShaders) {
Pipeline p(PipelineType::kGraphics);
Result r = p.Validate();
EXPECT_FALSE(r.IsSuccess()) << r.Error();
EXPECT_EQ("graphics pipeline requires vertex and fragment shaders",
r.Error());
}
TEST_F(AmberScriptPipelineTest, ComputePipelineRequiresComputeShader) {
Shader c(ShaderType::kCompute);
Pipeline p(PipelineType::kCompute);
Result r = p.AddShader(&c);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.Validate();
EXPECT_TRUE(r.IsSuccess()) << r.Error();
}
TEST_F(AmberScriptPipelineTest, ComputePipelineWithoutShader) {
Pipeline p(PipelineType::kCompute);
Result r = p.Validate();
EXPECT_FALSE(r.IsSuccess()) << r.Error();
EXPECT_EQ("compute pipeline requires a compute shader", r.Error());
}
TEST_F(AmberScriptPipelineTest, SetEntryPointForMissingShader) {
Shader c(ShaderType::kCompute);
c.SetName("my_shader");
Pipeline p(PipelineType::kCompute);
Result r = p.SetShaderEntryPoint(&c, "test");
EXPECT_FALSE(r.IsSuccess());
EXPECT_EQ("unknown shader specified for entry point: my_shader", r.Error());
}
TEST_F(AmberScriptPipelineTest, SetEntryPointForNullShader) {
Pipeline p(PipelineType::kCompute);
Result r = p.SetShaderEntryPoint(nullptr, "test");
EXPECT_FALSE(r.IsSuccess());
EXPECT_EQ("invalid shader specified for entry point", r.Error());
}
TEST_F(AmberScriptPipelineTest, SetBlankEntryPoint) {
Shader c(ShaderType::kCompute);
Pipeline p(PipelineType::kCompute);
Result r = p.AddShader(&c);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.SetShaderEntryPoint(&c, "");
EXPECT_FALSE(r.IsSuccess());
EXPECT_EQ("entry point should not be blank", r.Error());
}
TEST_F(AmberScriptPipelineTest, ShaderDefaultEntryPoint) {
Shader c(ShaderType::kCompute);
Pipeline p(PipelineType::kCompute);
Result r = p.AddShader(&c);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
const auto& shaders = p.GetShaders();
ASSERT_EQ(1U, shaders.size());
EXPECT_EQ("main", shaders[0].GetEntryPoint());
}
TEST_F(AmberScriptPipelineTest, SetShaderEntryPoint) {
Shader c(ShaderType::kCompute);
Pipeline p(PipelineType::kCompute);
Result r = p.AddShader(&c);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.SetShaderEntryPoint(&c, "my_main");
ASSERT_TRUE(r.IsSuccess()) << r.Error();
const auto& shaders = p.GetShaders();
ASSERT_EQ(1U, shaders.size());
EXPECT_EQ("my_main", shaders[0].GetEntryPoint());
}
TEST_F(AmberScriptPipelineTest, SetEntryPointMulitpleTimes) {
Shader c(ShaderType::kCompute);
Pipeline p(PipelineType::kCompute);
Result r = p.AddShader(&c);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.SetShaderEntryPoint(&c, "my_main");
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.SetShaderEntryPoint(&c, "another_main");
EXPECT_FALSE(r.IsSuccess());
EXPECT_EQ("multiple entry points given for the same shader", r.Error());
}
} // namespace amberscript
} // namespace amber