// 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 color_buffer_; std::unique_ptr 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; 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 first = {"First", "Second"}; std::vector 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 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(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(BufferType::kVertex); vtex_buf->SetName("vertex_buffer"); p.AddVertexBuffer(vtex_buf.get(), 1); auto idx_buf = MakeUnique(BufferType::kIndex); idx_buf->SetName("Index Buffer"); p.SetIndexBuffer(idx_buf.get()); auto buf1 = MakeUnique(BufferType::kStorage); buf1->SetName("buf1"); p.AddBuffer(buf1.get(), 1, 1); auto buf2 = MakeUnique(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(BufferType::kStorage); a_buf->SetName("buf1"); p.AddBuffer(a_buf.get(), "arg_a"); auto b_buf = MakeUnique(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(BufferType::kStorage); a_buf->SetName("buf1"); p.AddBuffer(a_buf.get(), "arg_a"); auto b_buf = MakeUnique(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(); int_fmt->AddComponent(FormatComponentType::kR, FormatMode::kSInt, 32); auto char_fmt = MakeUnique(); 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(*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(*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(*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(); 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(); 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(); int_fmt->AddComponent(FormatComponentType::kR, FormatMode::kSInt, 32); auto char_fmt = MakeUnique(); 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(*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(*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(*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