blob: 8bba23e1f0219aa5db0d6683c03fb25c2f81f6c9 [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/pipeline.h"
#include "gtest/gtest.h"
#include "src/make_unique.h"
namespace amber {
namespace {
struct ShaderTypeData {
ShaderType type;
};
} // namespace
class PipelineTest : public testing::Test {
public:
void TearDown() override {
color_buffer_ = nullptr;
depth_buffer_ = nullptr;
}
void SetupColorAttachment(Pipeline* p, uint32_t location) {
if (!color_buffer_)
color_buffer_ = p->GenerateDefaultColorAttachmentBuffer();
p->AddColorAttachment(color_buffer_.get(), location);
}
void SetupDepthAttachment(Pipeline* p) {
if (!depth_buffer_)
depth_buffer_ = p->GenerateDefaultDepthAttachmentBuffer();
p->SetDepthBuffer(depth_buffer_.get());
}
private:
std::unique_ptr<Buffer> color_buffer_;
std::unique_ptr<Buffer> depth_buffer_;
};
TEST_F(PipelineTest, AddShader) {
Shader v(kShaderTypeVertex);
Shader f(kShaderTypeFragment);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&v, kShaderTypeVertex);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&f, kShaderTypeFragment);
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(PipelineTest, MissingShader) {
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(nullptr, kShaderTypeVertex);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("shader can not be null when attached to pipeline", r.Error());
}
TEST_F(PipelineTest, DuplicateShaders) {
Shader v(kShaderTypeVertex);
Shader f(kShaderTypeFragment);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&v, kShaderTypeVertex);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&f, kShaderTypeFragment);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&v, kShaderTypeVertex);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("can not add duplicate shader 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, test_data.type);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("only compute shaders allowed in a compute pipeline", r.Error());
}
INSTANTIATE_TEST_SUITE_P(
AmberScriptPipelineComputePipelineTests,
AmberScriptPipelineComputePipelineTest,
testing::Values(
ShaderTypeData{kShaderTypeVertex},
ShaderTypeData{kShaderTypeFragment},
ShaderTypeData{kShaderTypeGeometry},
ShaderTypeData{kShaderTypeTessellationEvaluation},
ShaderTypeData{
kShaderTypeTessellationControl})); // NOLINT(whitespace/parens)
TEST_F(PipelineTest, SettingComputeShaderToGraphicsPipeline) {
Shader c(kShaderTypeCompute);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&c, kShaderTypeCompute);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("can not add a compute shader to a graphics pipeline", r.Error());
}
TEST_F(PipelineTest, SetShaderOptimizations) {
Shader v(kShaderTypeVertex);
Shader f(kShaderTypeFragment);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&v, kShaderTypeVertex);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&f, kShaderTypeFragment);
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(PipelineTest, DuplicateShaderOptimizations) {
Shader v(kShaderTypeVertex);
Pipeline p(PipelineType::kGraphics);
Result r = p.AddShader(&v, kShaderTypeVertex);
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(PipelineTest, 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(PipelineTest, SetOptimizationForInvalidShader) {
Shader v(kShaderTypeVertex);
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(PipelineTest, GraphicsPipelineRequiresColorAttachment) {
Pipeline p(PipelineType::kGraphics);
SetupDepthAttachment(&p);
Result r = p.Validate();
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("PIPELINE missing color attachment", r.Error());
}
TEST_F(PipelineTest, GraphicsPipelineRequiresVertexAndFragmentShader) {
Shader v(kShaderTypeVertex);
Shader f(kShaderTypeFragment);
Shader g(kShaderTypeGeometry);
Pipeline p(PipelineType::kGraphics);
SetupColorAttachment(&p, 0);
SetupDepthAttachment(&p);
Result r = p.AddShader(&v, kShaderTypeVertex);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&g, kShaderTypeGeometry);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&f, kShaderTypeFragment);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.Validate();
EXPECT_TRUE(r.IsSuccess()) << r.Error();
}
TEST_F(PipelineTest, GraphicsPipelineMissingVertexShader) {
Shader f(kShaderTypeFragment);
Shader g(kShaderTypeGeometry);
Pipeline p(PipelineType::kGraphics);
SetupColorAttachment(&p, 0);
SetupDepthAttachment(&p);
Result r = p.AddShader(&g, kShaderTypeGeometry);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.AddShader(&f, kShaderTypeFragment);
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(PipelineTest, ComputePipelineRequiresComputeShader) {
Shader c(kShaderTypeCompute);
Pipeline p(PipelineType::kCompute);
SetupColorAttachment(&p, 0);
SetupDepthAttachment(&p);
Result r = p.AddShader(&c, kShaderTypeCompute);
EXPECT_TRUE(r.IsSuccess()) << r.Error();
r = p.Validate();
EXPECT_TRUE(r.IsSuccess()) << r.Error();
}
TEST_F(PipelineTest, ComputePipelineWithoutShader) {
Pipeline p(PipelineType::kCompute);
SetupColorAttachment(&p, 0);
SetupDepthAttachment(&p);
Result r = p.Validate();
EXPECT_FALSE(r.IsSuccess()) << r.Error();
EXPECT_EQ("compute pipeline requires a compute shader", r.Error());
}
TEST_F(PipelineTest, PipelineBufferWithoutFormat) {
Pipeline p(PipelineType::kCompute);
auto buf = MakeUnique<Buffer>(BufferType::kStorage);
buf->SetName("MyBuffer");
p.AddBuffer(buf.get(), 0, 0);
Result r = p.Validate();
EXPECT_FALSE(r.IsSuccess()) << r.Error();
EXPECT_EQ("buffer (0:0) requires a format", r.Error());
}
TEST_F(PipelineTest, SetEntryPointForMissingShader) {
Shader c(kShaderTypeCompute);
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(PipelineTest, 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(PipelineTest, SetBlankEntryPoint) {
Shader c(kShaderTypeCompute);
Pipeline p(PipelineType::kCompute);
Result r = p.AddShader(&c, kShaderTypeCompute);
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(PipelineTest, ShaderDefaultEntryPoint) {
Shader c(kShaderTypeCompute);
Pipeline p(PipelineType::kCompute);
Result r = p.AddShader(&c, kShaderTypeCompute);
ASSERT_TRUE(r.IsSuccess()) << r.Error();
const auto& shaders = p.GetShaders();
ASSERT_EQ(1U, shaders.size());
EXPECT_EQ("main", shaders[0].GetEntryPoint());
}
TEST_F(PipelineTest, SetShaderEntryPoint) {
Shader c(kShaderTypeCompute);
Pipeline p(PipelineType::kCompute);
Result r = p.AddShader(&c, kShaderTypeCompute);
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(PipelineTest, SetEntryPointMulitpleTimes) {
Shader c(kShaderTypeCompute);
Pipeline p(PipelineType::kCompute);
Result r = p.AddShader(&c, kShaderTypeCompute);
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());
}
TEST_F(PipelineTest, Clone) {
Pipeline p(PipelineType::kGraphics);
p.SetName("my_pipeline");
p.SetFramebufferWidth(800);
p.SetFramebufferHeight(600);
SetupColorAttachment(&p, 0);
SetupDepthAttachment(&p);
Shader f(kShaderTypeFragment);
p.AddShader(&f, kShaderTypeFragment);
Shader v(kShaderTypeVertex);
p.AddShader(&v, kShaderTypeVertex);
p.SetShaderEntryPoint(&v, "my_main");
auto vtex_buf = MakeUnique<Buffer>(BufferType::kVertex);
vtex_buf->SetName("vertex_buffer");
p.AddVertexBuffer(vtex_buf.get(), 1);
auto idx_buf = MakeUnique<Buffer>(BufferType::kIndex);
idx_buf->SetName("Index Buffer");
p.SetIndexBuffer(idx_buf.get());
auto buf1 = MakeUnique<Buffer>(BufferType::kStorage);
buf1->SetName("buf1");
p.AddBuffer(buf1.get(), 1, 1);
auto buf2 = MakeUnique<Buffer>(BufferType::kStorage);
buf2->SetName("buf2");
p.AddBuffer(buf2.get(), 1, 2);
auto clone = p.Clone();
EXPECT_EQ("", clone->GetName());
EXPECT_EQ(800U, clone->GetFramebufferWidth());
EXPECT_EQ(600U, clone->GetFramebufferHeight());
auto shaders = clone->GetShaders();
ASSERT_EQ(2U, shaders.size());
EXPECT_EQ(kShaderTypeFragment, shaders[0].GetShaderType());
EXPECT_EQ(kShaderTypeVertex, shaders[1].GetShaderType());
EXPECT_EQ("my_main", shaders[1].GetEntryPoint());
ASSERT_TRUE(clone->GetIndexBuffer() != nullptr);
EXPECT_EQ("Index Buffer", clone->GetIndexBuffer()->GetName());
auto vtex_buffers = clone->GetVertexBuffers();
ASSERT_EQ(1U, vtex_buffers.size());
EXPECT_EQ(1, vtex_buffers[0].location);
EXPECT_EQ("vertex_buffer", vtex_buffers[0].buffer->GetName());
auto bufs = clone->GetBuffers();
ASSERT_EQ(2U, bufs.size());
EXPECT_EQ("buf1", bufs[0].buffer->GetName());
EXPECT_EQ(1U, bufs[0].descriptor_set);
EXPECT_EQ(1U, bufs[0].binding);
EXPECT_EQ("buf2", bufs[1].buffer->GetName());
EXPECT_EQ(1U, bufs[1].descriptor_set);
EXPECT_EQ(2U, bufs[1].binding);
}
TEST_F(PipelineTest, OpenCLUpdateBindings) {
Pipeline p(PipelineType::kCompute);
p.SetName("my_pipeline");
Shader cs(kShaderTypeCompute);
cs.SetFormat(kShaderFormatOpenCLC);
p.AddShader(&cs, kShaderTypeCompute);
p.SetShaderEntryPoint(&cs, "my_main");
Pipeline::ShaderInfo::DescriptorMapEntry entry1;
entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SSBO;
entry1.descriptor_set = 4;
entry1.binding = 5;
entry1.arg_name = "arg_a";
entry1.arg_ordinal = 0;
p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
Pipeline::ShaderInfo::DescriptorMapEntry entry2;
entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SSBO;
entry2.descriptor_set = 3;
entry2.binding = 1;
entry2.arg_name = "arg_b";
entry2.arg_ordinal = 1;
p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
auto a_buf = MakeUnique<Buffer>(BufferType::kStorage);
a_buf->SetName("buf1");
p.AddBuffer(a_buf.get(), "arg_a");
auto b_buf = MakeUnique<Buffer>(BufferType::kStorage);
b_buf->SetName("buf2");
p.AddBuffer(b_buf.get(), 1);
p.UpdateOpenCLBufferBindings();
auto& bufs = p.GetBuffers();
ASSERT_EQ(2U, bufs.size());
EXPECT_EQ("buf1", bufs[0].buffer->GetName());
EXPECT_EQ(4U, bufs[0].descriptor_set);
EXPECT_EQ(5U, bufs[0].binding);
EXPECT_EQ("buf2", bufs[1].buffer->GetName());
EXPECT_EQ(3U, bufs[1].descriptor_set);
EXPECT_EQ(1U, bufs[1].binding);
}
TEST_F(PipelineTest, OpenCLUpdateBindingTypeMismatch) {
Pipeline p(PipelineType::kCompute);
p.SetName("my_pipeline");
Shader cs(kShaderTypeCompute);
cs.SetFormat(kShaderFormatOpenCLC);
p.AddShader(&cs, kShaderTypeCompute);
p.SetShaderEntryPoint(&cs, "my_main");
Pipeline::ShaderInfo::DescriptorMapEntry entry1;
entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SSBO;
entry1.descriptor_set = 4;
entry1.binding = 5;
entry1.arg_name = "arg_a";
entry1.arg_ordinal = 0;
p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
Pipeline::ShaderInfo::DescriptorMapEntry entry2;
entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::SSBO;
entry2.descriptor_set = 3;
entry2.binding = 1;
entry2.arg_name = "arg_b";
entry2.arg_ordinal = 1;
p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
auto a_buf = MakeUnique<Buffer>(BufferType::kStorage);
a_buf->SetName("buf1");
p.AddBuffer(a_buf.get(), "arg_a");
auto b_buf = MakeUnique<Buffer>(BufferType::kUniform);
b_buf->SetName("buf2");
p.AddBuffer(b_buf.get(), 1);
auto r = p.UpdateOpenCLBufferBindings();
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("Buffer buf2 must be an uniform binding", r.Error());
}
TEST_F(PipelineTest, OpenCLGeneratePodBuffers) {
Pipeline p(PipelineType::kCompute);
p.SetName("my_pipeline");
Shader cs(kShaderTypeCompute);
cs.SetFormat(kShaderFormatOpenCLC);
p.AddShader(&cs, kShaderTypeCompute);
p.SetShaderEntryPoint(&cs, "my_main");
// Descriptor map.
Pipeline::ShaderInfo::DescriptorMapEntry entry1;
entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
entry1.descriptor_set = 4;
entry1.binding = 5;
entry1.arg_name = "arg_a";
entry1.arg_ordinal = 0;
entry1.pod_offset = 0;
entry1.pod_arg_size = 4;
p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
Pipeline::ShaderInfo::DescriptorMapEntry entry2;
entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
entry2.descriptor_set = 4;
entry2.binding = 5;
entry2.arg_name = "arg_b";
entry2.arg_ordinal = 0;
entry2.pod_offset = 4;
entry2.pod_arg_size = 1;
p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
Pipeline::ShaderInfo::DescriptorMapEntry entry3;
entry3.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
entry3.descriptor_set = 4;
entry3.binding = 4;
entry3.arg_name = "arg_c";
entry3.arg_ordinal = 0;
entry3.pod_offset = 0;
entry3.pod_arg_size = 4;
p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry3));
// Set commands.
Value int_value;
int_value.SetIntValue(1);
auto int_fmt = MakeUnique<Format>();
int_fmt->AddComponent(FormatComponentType::kR, FormatMode::kSInt, 32);
auto char_fmt = MakeUnique<Format>();
char_fmt->AddComponent(FormatComponentType::kR, FormatMode::kSInt, 8);
Pipeline::ArgSetInfo arg_info1;
arg_info1.name = "arg_a";
arg_info1.ordinal = 99;
arg_info1.fmt = MakeUnique<Format>(*int_fmt);
arg_info1.value = int_value;
p.SetArg(std::move(arg_info1));
Pipeline::ArgSetInfo arg_info2;
arg_info2.name = "arg_b";
arg_info2.ordinal = 99;
arg_info2.fmt = MakeUnique<Format>(*char_fmt);
arg_info2.value = int_value;
p.SetArg(std::move(arg_info2));
Pipeline::ArgSetInfo arg_info3;
arg_info3.name = "arg_c";
arg_info3.ordinal = 99;
arg_info3.fmt = MakeUnique<Format>(*int_fmt);
arg_info3.value = int_value;
p.SetArg(std::move(arg_info3));
auto r = p.GenerateOpenCLPodBuffers();
ASSERT_TRUE(r.IsSuccess());
EXPECT_EQ(2U, p.GetBuffers().size());
const auto& b1 = p.GetBuffers()[0];
EXPECT_EQ(4U, b1.descriptor_set);
EXPECT_EQ(5U, b1.binding);
EXPECT_EQ(5U, b1.buffer->ValueCount());
const auto& b2 = p.GetBuffers()[1];
EXPECT_EQ(4U, b2.descriptor_set);
EXPECT_EQ(4U, b2.binding);
EXPECT_EQ(4U, b2.buffer->ValueCount());
}
TEST_F(PipelineTest, OpenCLGeneratePodBuffersBadName) {
Pipeline p(PipelineType::kCompute);
p.SetName("my_pipeline");
Shader cs(kShaderTypeCompute);
cs.SetFormat(kShaderFormatOpenCLC);
p.AddShader(&cs, kShaderTypeCompute);
p.SetShaderEntryPoint(&cs, "my_main");
// Descriptor map.
Pipeline::ShaderInfo::DescriptorMapEntry entry1;
entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
entry1.descriptor_set = 4;
entry1.binding = 5;
entry1.arg_name = "arg_a";
entry1.arg_ordinal = 0;
entry1.pod_offset = 0;
entry1.pod_arg_size = 4;
p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
// Set commands.
Value int_value;
int_value.SetIntValue(1);
auto int_fmt = MakeUnique<Format>();
int_fmt->AddComponent(FormatComponentType::kR, FormatMode::kSInt, 32);
Pipeline::ArgSetInfo arg_info1;
arg_info1.name = "arg_z";
arg_info1.ordinal = 99;
arg_info1.fmt = std::move(int_fmt);
arg_info1.value = int_value;
p.SetArg(std::move(arg_info1));
auto r = p.GenerateOpenCLPodBuffers();
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ(
"could not find descriptor map entry for SET command: kernel my_main, "
"name arg_z",
r.Error());
}
TEST_F(PipelineTest, OpenCLGeneratePodBuffersBadSize) {
Pipeline p(PipelineType::kCompute);
p.SetName("my_pipeline");
Shader cs(kShaderTypeCompute);
cs.SetFormat(kShaderFormatOpenCLC);
p.AddShader(&cs, kShaderTypeCompute);
p.SetShaderEntryPoint(&cs, "my_main");
// Descriptor map.
Pipeline::ShaderInfo::DescriptorMapEntry entry1;
entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
entry1.descriptor_set = 4;
entry1.binding = 5;
entry1.arg_name = "arg_a";
entry1.arg_ordinal = 0;
entry1.pod_offset = 0;
entry1.pod_arg_size = 4;
p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
// Set commands.
Value int_value;
int_value.SetIntValue(1);
auto short_fmt = MakeUnique<Format>();
short_fmt->AddComponent(FormatComponentType::kR, FormatMode::kSInt, 16);
Pipeline::ArgSetInfo arg_info1;
arg_info1.name = "";
arg_info1.ordinal = 0;
arg_info1.fmt = std::move(short_fmt);
arg_info1.value = int_value;
p.SetArg(std::move(arg_info1));
auto r = p.GenerateOpenCLPodBuffers();
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("SET command uses incorrect data size: kernel my_main, number 0",
r.Error());
}
TEST_F(PipelineTest, OpenCLClone) {
Pipeline p(PipelineType::kCompute);
p.SetName("my_pipeline");
Shader cs(kShaderTypeCompute);
cs.SetFormat(kShaderFormatOpenCLC);
p.AddShader(&cs, kShaderTypeCompute);
p.SetShaderEntryPoint(&cs, "my_main");
// Descriptor map.
Pipeline::ShaderInfo::DescriptorMapEntry entry1;
entry1.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
entry1.descriptor_set = 4;
entry1.binding = 5;
entry1.arg_name = "arg_a";
entry1.arg_ordinal = 0;
entry1.pod_offset = 0;
entry1.pod_arg_size = 4;
p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry1));
Pipeline::ShaderInfo::DescriptorMapEntry entry2;
entry2.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
entry2.descriptor_set = 4;
entry2.binding = 5;
entry2.arg_name = "arg_b";
entry2.arg_ordinal = 0;
entry2.pod_offset = 4;
entry2.pod_arg_size = 1;
p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry2));
Pipeline::ShaderInfo::DescriptorMapEntry entry3;
entry3.kind = Pipeline::ShaderInfo::DescriptorMapEntry::Kind::POD;
entry3.descriptor_set = 4;
entry3.binding = 4;
entry3.arg_name = "arg_c";
entry3.arg_ordinal = 0;
entry3.pod_offset = 0;
entry3.pod_arg_size = 4;
p.GetShaders()[0].AddDescriptorEntry("my_main", std::move(entry3));
// Set commands.
Value int_value;
int_value.SetIntValue(1);
auto int_fmt = MakeUnique<Format>();
int_fmt->AddComponent(FormatComponentType::kR, FormatMode::kSInt, 32);
auto char_fmt = MakeUnique<Format>();
char_fmt->AddComponent(FormatComponentType::kR, FormatMode::kSInt, 8);
Pipeline::ArgSetInfo arg_info1;
arg_info1.name = "arg_a";
arg_info1.ordinal = 99;
arg_info1.fmt = MakeUnique<Format>(*int_fmt);
arg_info1.value = int_value;
p.SetArg(std::move(arg_info1));
Pipeline::ArgSetInfo arg_info2;
arg_info2.name = "arg_b";
arg_info2.ordinal = 99;
arg_info2.fmt = MakeUnique<Format>(*char_fmt);
arg_info2.value = int_value;
p.SetArg(std::move(arg_info2));
Pipeline::ArgSetInfo arg_info3;
arg_info3.name = "arg_c";
arg_info3.ordinal = 99;
arg_info3.fmt = MakeUnique<Format>(*int_fmt);
arg_info3.value = int_value;
p.SetArg(std::move(arg_info3));
auto clone = p.Clone();
auto r = clone->GenerateOpenCLPodBuffers();
ASSERT_TRUE(r.IsSuccess());
EXPECT_EQ(3U, clone->SetArgValues().size());
EXPECT_EQ(2U, clone->GetBuffers().size());
const auto& b1 = clone->GetBuffers()[0];
EXPECT_EQ(4U, b1.descriptor_set);
EXPECT_EQ(5U, b1.binding);
EXPECT_EQ(5U, b1.buffer->ValueCount());
const auto& b2 = clone->GetBuffers()[1];
EXPECT_EQ(4U, b2.descriptor_set);
EXPECT_EQ(4U, b2.binding);
EXPECT_EQ(4U, b2.buffer->ValueCount());
}
} // namespace amber