diff options
author | dan sinclair <dj2@everburning.com> | 2019-04-09 18:09:47 -0400 |
---|---|---|
committer | David Neto <dneto@google.com> | 2019-04-09 18:09:47 -0400 |
commit | 43248b29723575d27eb96187ef9ca594739140ed (patch) | |
tree | 1f00ee30857a26b62a8a170d263698d52f9e17c0 | |
parent | 539730372bb8145fa029759be17dff320c970895 (diff) | |
download | amber-43248b29723575d27eb96187ef9ca594739140ed.tar.gz |
[AmberScript] Add DERIVE_PIPELINE (#453)
This CL adds the DERIVE_PIPELINE command to allow pipelines to be based
off of previously declared pipelines.
Fixes #435.
-rw-r--r-- | docs/amber_script.md | 16 | ||||
-rw-r--r-- | src/amberscript/parser.cc | 99 | ||||
-rw-r--r-- | src/amberscript/parser.h | 3 | ||||
-rw-r--r-- | src/amberscript/parser_bind_test.cc | 104 | ||||
-rw-r--r-- | src/amberscript/parser_buffer_test.cc | 28 | ||||
-rw-r--r-- | src/amberscript/parser_pipeline_test.cc | 169 | ||||
-rw-r--r-- | src/pipeline.cc | 47 | ||||
-rw-r--r-- | src/pipeline.h | 23 | ||||
-rw-r--r-- | src/pipeline_test.cc | 132 | ||||
-rw-r--r-- | src/vkscript/command_parser.cc | 4 | ||||
-rw-r--r-- | src/vkscript/parser.cc | 6 | ||||
-rw-r--r-- | src/vulkan/engine_vulkan.cc | 2 | ||||
-rw-r--r-- | src/vulkan/graphics_pipeline.cc | 4 | ||||
-rw-r--r-- | tests/cases/draw_rectangles.amber | 80 | ||||
-rw-r--r-- | tools/amber-syntax.vim | 2 | ||||
-rw-r--r-- | tools/amber.sublime-syntax | 4 |
16 files changed, 490 insertions, 233 deletions
diff --git a/docs/amber_script.md b/docs/amber_script.md index c7d1399..c755d2a 100644 --- a/docs/amber_script.md +++ b/docs/amber_script.md @@ -159,8 +159,14 @@ argument to an EXPECT command. PIPELINE <pipeline_type> <pipeline_name> ... END + +# Create a pipeline and inherit from a previously declared pipeline. +DERIVE_PIPELINE <<pipeline_name> FROM <parent_pipeline> +... +END ``` + ### Pipeline Content The following commands are all specified within the `PIPELINE` command. @@ -225,10 +231,6 @@ attachment content, depth/stencil content, uniform buffers, etc. # and binding. The buffer will use a start index of 0. BIND BUFFER <buffer_name> AS <buffer_type> DESCRIPTOR_SET <id> \ BINDING <id> - # Bind the buffer of the given |buffer_type| at the given descriptor set - # and binding and index at the given value. - BIND BUFFER <buffer_name> AS <buffer_type> DESCRIPTOR_SET <id> \ - BINDING <id> IDX <val> # Bind the sampler at the given descriptor set and binding. BIND SAMPLER <sampler_name> DESCRIPTOR_SET <id> BINDING <id> @@ -482,7 +484,7 @@ PIPELINE graphics kRedPipeline ATTACH kFragmentShader ENTRY_POINT red FRAMEBUFFER_SIZE 256 256 - BIND BUFFER kImgBuffer AS image IDX 0 + BIND BUFFER kImgBuffer AS color LOCATION 0 END # pipeline PIPELINE graphics kGreenPipeline @@ -490,7 +492,7 @@ PIPELINE graphics kGreenPipeline ATTACH kFragmentShader ENTRY_POINT green FRAMEBUFFER_SIZE 256 256 - BIND BUFFER kImgBuffer AS image IDX 0 + BIND BUFFER kImgBuffer AS color LOCATION 0 END # pipeline RUN kRedPipeline DRAW_RECT POS 0 0 SIZE 256 256 @@ -597,7 +599,7 @@ CLEAR_COLOR kGraphicsPipeline 255 0 0 255 CLEAR kGraphicsPipeline RUN kGraphicsPipeline DRAW_ARRAY AS triangle_list START_IDX 0 COUNT 24 - ``` +``` ### Image Formats * A1R5G5B5_UNORM_PACK16 diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc index c0fa6c9..bd33320 100644 --- a/src/amberscript/parser.cc +++ b/src/amberscript/parser.cc @@ -76,6 +76,8 @@ Result Parser::Parse(const std::string& data) { r = ParseRepeatableCommand(tok); } else if (tok == "BUFFER") { r = ParseBuffer(); + } else if (tok == "DERIVE_PIPELINE") { + r = ParseDerivePipelineBlock(); } else if (tok == "DEVICE_FEATURE") { r = ParseDeviceFeature(); } else if (tok == "PIPELINE") { @@ -92,7 +94,7 @@ Result Parser::Parse(const std::string& data) { } script_->SetCommands(std::move(command_list_)); - // Generate any needed color and depth attachments. This is done before + // Generate any needed color attachments. This is done before // validating in case one of the pipelines specifies the framebuffer size // it needs to be verified against all other pipelines. for (const auto& pipeline : script_->GetPipelines()) { @@ -111,23 +113,6 @@ Result Parser::Parse(const std::string& data) { if (!r.IsSuccess()) return r; } - - // Add a depth buffer if needed - if (pipeline->GetDepthBuffer().buffer == nullptr) { - auto* buf = script_->GetBuffer(Pipeline::kGeneratedDepthBuffer); - if (!buf) { - auto new_buf = pipeline->GenerateDefaultDepthAttachmentBuffer(); - buf = new_buf.get(); - - Result r = script_->AddBuffer(std::move(new_buf)); - if (!r.IsSuccess()) - return r; - } - - Result r = pipeline->SetDepthBuffer(buf); - if (!r.IsSuccess()) - return r; - } } // Validate all the pipelines at the end. This allows us to verify the @@ -391,6 +376,12 @@ Result Parser::ParsePipelineBlock() { if (!r.IsSuccess()) return r; + return ParsePipelineBody("PIPELINE", std::move(pipeline)); +} + +Result Parser::ParsePipelineBody(const std::string& cmd_name, + std::unique_ptr<Pipeline> pipeline) { + std::unique_ptr<Token> token; for (token = tokenizer_->NextToken(); !token->IsEOS(); token = tokenizer_->NextToken()) { if (token->IsEOL()) @@ -398,6 +389,7 @@ Result Parser::ParsePipelineBlock() { if (!token->IsString()) return Result("expected string"); + Result r; std::string tok = token->AsString(); if (tok == "END") { break; @@ -421,9 +413,9 @@ Result Parser::ParsePipelineBlock() { } if (!token->IsString() || token->AsString() != "END") - return Result("PIPELINE missing END command"); + return Result(cmd_name + " missing END command"); - r = script_->AddPipeline(std::move(pipeline)); + Result r = script_->AddPipeline(std::move(pipeline)); if (!r.IsSuccess()) return r; @@ -637,21 +629,7 @@ Result Parser::ParsePipelineBind(Pipeline* pipeline) { token = tokenizer_->NextToken(); if (!token->IsInteger()) return Result("invalid value for BINDING in BIND command"); - uint32_t binding = token->AsUint32(); - - token = tokenizer_->NextToken(); - if (token->IsEOL() || token->IsEOS()) { - pipeline->AddBuffer(buffer, descriptor_set, binding, 0); - return {}; - } - if (!token->IsString() || token->AsString() != "IDX") - return Result("extra parameters after BIND command"); - - token = tokenizer_->NextToken(); - if (!token->IsInteger()) - return Result("invalid value for IDX in BIND command"); - - pipeline->AddBuffer(buffer, descriptor_set, binding, token->AsUint32()); + pipeline->AddBuffer(buffer, descriptor_set, token->AsUint32()); } return ValidateEndOfStatement("BIND command"); @@ -886,6 +864,8 @@ Result Parser::ParseBufferInitializerData(DataBuffer* buffer) { Value v; if (is_double_type) { + token->ConvertToDouble(); + double val = token->IsHex() ? static_cast<double>(token->AsHex()) : token->AsDouble(); v.SetDoubleValue(val); @@ -910,6 +890,8 @@ Result Parser::ParseRun() { if (!token->IsString()) return Result("missing pipeline name for RUN command"); + size_t line = tokenizer_->GetCurrentLine(); + auto* pipeline = script_->GetPipeline(token->AsString()); if (!pipeline) return Result("unknown pipeline for RUN command: " + token->AsString()); @@ -923,6 +905,7 @@ Result Parser::ParseRun() { return Result("RUN command requires compute pipeline"); auto cmd = MakeUnique<ComputeCommand>(pipeline); + cmd->SetLine(line); cmd->SetX(token->AsUint32()); token = tokenizer_->NextToken(); @@ -963,6 +946,7 @@ Result Parser::ParseRun() { return Result("missing X position for RUN command"); auto cmd = MakeUnique<DrawRectCommand>(pipeline, PipelineData{}); + cmd->SetLine(line); cmd->EnableOrtho(); Result r = token->ConvertToDouble(); @@ -1012,6 +996,7 @@ Result Parser::ParseRun() { return Result("RUN command requires graphics pipeline"); auto cmd = MakeUnique<DrawArraysCommand>(pipeline, PipelineData{}); + cmd->SetLine(line); command_list_.push_back(std::move(cmd)); return ValidateEndOfStatement("RUN command"); @@ -1022,10 +1007,11 @@ Result Parser::ParseRun() { Result Parser::ParseClear() { auto token = tokenizer_->NextToken(); - if (!token->IsString()) return Result("missing pipeline name for CLEAR command"); + size_t line = tokenizer_->GetCurrentLine(); + auto* pipeline = script_->GetPipeline(token->AsString()); if (!pipeline) return Result("unknown pipeline for CLEAR command: " + token->AsString()); @@ -1033,6 +1019,7 @@ Result Parser::ParseClear() { return Result("CLEAR command requires graphics pipeline"); auto cmd = MakeUnique<ClearCommand>(pipeline); + cmd->SetLine(line); command_list_.push_back(std::move(cmd)); return ValidateEndOfStatement("CLEAR command"); @@ -1083,6 +1070,7 @@ Result Parser::ParseExpect() { if (token->AsString() == "EQ_BUFFER") return Result("missing buffer name between EXPECT and EQ_BUFFER"); + size_t line = tokenizer_->GetCurrentLine(); auto* buffer = script_->GetBuffer(token->AsString()); if (!buffer) return Result("unknown buffer name for EXPECT command: " + @@ -1154,6 +1142,7 @@ Result Parser::ParseExpect() { return Result("invalid Y value in EXPECT command"); auto probe = MakeUnique<ProbeCommand>(buffer); + probe->SetLine(line); probe->SetX(x); probe->SetY(y); probe->SetProbeRect(); @@ -1217,6 +1206,7 @@ Result Parser::ParseExpect() { return Result("comparator must be provided a data buffer"); auto probe = MakeUnique<ProbeSSBOCommand>(buffer); + probe->SetLine(line); probe->SetComparator(ToComparator(token->AsString())); probe->SetDatumType(buffer->AsDataBuffer()->GetDatumType()); probe->SetOffset(static_cast<uint32_t>(x)); @@ -1247,6 +1237,8 @@ Result Parser::ParseCopy() { if (!token->IsString()) return Result("invalid buffer name after COPY"); + size_t line = tokenizer_->GetCurrentLine(); + auto name = token->AsString(); if (name == "TO") return Result("missing buffer name between COPY and TO"); @@ -1290,6 +1282,7 @@ Result Parser::ParseCopy() { return Result("COPY origin and destination buffers are identical"); auto cmd = MakeUnique<CopyCommand>(buffer_from, buffer_to); + cmd->SetLine(line); command_list_.push_back(std::move(cmd)); return ValidateEndOfStatement("COPY command"); @@ -1300,6 +1293,8 @@ Result Parser::ParseClearColor() { if (!token->IsString()) return Result("missing pipeline name for CLEAR_COLOR command"); + size_t line = tokenizer_->GetCurrentLine(); + auto* pipeline = script_->GetPipeline(token->AsString()); if (!pipeline) { return Result("unknown pipeline for CLEAR_COLOR command: " + @@ -1310,6 +1305,7 @@ Result Parser::ParseClearColor() { } auto cmd = MakeUnique<ClearColorCommand>(pipeline); + cmd->SetLine(line); token = tokenizer_->NextToken(); if (token->IsEOL() || token->IsEOS()) @@ -1414,5 +1410,36 @@ Result Parser::ParseRepeat() { return ValidateEndOfStatement("REPEAT command"); } +Result Parser::ParseDerivePipelineBlock() { + auto token = tokenizer_->NextToken(); + if (!token->IsString() || token->AsString() == "FROM") + return Result("missing pipeline name for DERIVE_PIPELINE command"); + + std::string name = token->AsString(); + if (script_->GetPipeline(name) != nullptr) + return Result("duplicate pipeline name for DERIVE_PIPELINE command"); + + token = tokenizer_->NextToken(); + if (!token->IsString() || token->AsString() != "FROM") + return Result("missing FROM in DERIVE_PIPELINE command"); + + token = tokenizer_->NextToken(); + if (!token->IsString()) + return Result("missing parent pipeline name in DERIVE_PIPELINE command"); + + Pipeline* parent = script_->GetPipeline(token->AsString()); + if (!parent) + return Result("unknown parent pipeline in DERIVE_PIPELINE command"); + + Result r = ValidateEndOfStatement("DERIVE_PIPELINE command"); + if (!r.IsSuccess()) + return r; + + auto pipeline = parent->Clone(); + pipeline->SetName(name); + + return ParsePipelineBody("DERIVE_PIPELINE", std::move(pipeline)); +} + } // namespace amberscript } // namespace amber diff --git a/src/amberscript/parser.h b/src/amberscript/parser.h index faf25f2..289011c 100644 --- a/src/amberscript/parser.h +++ b/src/amberscript/parser.h @@ -70,6 +70,9 @@ class Parser : public amber::Parser { Result ParseRepeat(); bool IsRepeatable(const std::string& name) const; Result ParseRepeatableCommand(const std::string& name); + Result ParseDerivePipelineBlock(); + Result ParsePipelineBody(const std::string& cmd_name, + std::unique_ptr<Pipeline> pipeline); // Parses a set of values out of the token stream. |name| is the name of the // current command we're parsing for error purposes. The |type| is the type diff --git a/src/amberscript/parser_bind_test.cc b/src/amberscript/parser_bind_test.cc index b5be6bc..90485a3 100644 --- a/src/amberscript/parser_bind_test.cc +++ b/src/amberscript/parser_bind_test.cc @@ -923,62 +923,6 @@ END bufs[0].buffer->AsFormatBuffer()->GetFormat().GetFormatType()); } -TEST_F(AmberScriptParserTest, BindBufferWithIdx) { - std::string in = R"( -SHADER vertex my_shader PASSTHROUGH -SHADER fragment my_fragment GLSL -# GLSL Shader -END -BUFFER my_buf FORMAT R32G32B32A32_SFLOAT - -PIPELINE graphics my_pipeline - ATTACH my_shader - ATTACH my_fragment - - BIND BUFFER my_buf AS uniform DESCRIPTOR_SET 1 BINDING 2 IDX 5 -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& bufs = pipeline->GetBuffers(); - ASSERT_EQ(1U, bufs.size()); - EXPECT_EQ(BufferType::kUniform, bufs[0].buffer->GetBufferType()); - EXPECT_EQ(1U, bufs[0].descriptor_set); - EXPECT_EQ(2U, bufs[0].binding); - EXPECT_EQ(5U, bufs[0].location); - EXPECT_TRUE(bufs[0].buffer->IsFormatBuffer()); - EXPECT_EQ(FormatType::kR32G32B32A32_SFLOAT, - bufs[0].buffer->AsFormatBuffer()->GetFormat().GetFormatType()); -} - -TEST_F(AmberScriptParserTest, BindBufferMissingIdxValue) { - std::string in = R"( -SHADER vertex my_shader PASSTHROUGH -SHADER fragment my_fragment GLSL -# GLSL Shader -END -BUFFER my_buf FORMAT R32G32B32A32_SFLOAT - -PIPELINE graphics my_pipeline - ATTACH my_shader - ATTACH my_fragment - - BIND BUFFER my_buf AS uniform DESCRIPTOR_SET 1 BINDING 2 IDX -END)"; - - Parser parser; - Result r = parser.Parse(in); - ASSERT_FALSE(r.IsSuccess()); - EXPECT_EQ("13: invalid value for IDX in BIND command", r.Error()); -} - TEST_F(AmberScriptParserTest, BindBufferMissingBindingValue) { std::string in = R"( SHADER vertex my_shader PASSTHROUGH @@ -1012,13 +956,13 @@ PIPELINE graphics my_pipeline ATTACH my_shader ATTACH my_fragment - BIND BUFFER my_buf AS uniform DESCRIPTOR_SET 1 IDX 5 + BIND BUFFER my_buf AS uniform DESCRIPTOR_SET 1 END)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()); - EXPECT_EQ("12: missing BINDING for BIND command", r.Error()); + EXPECT_EQ("13: missing BINDING for BIND command", r.Error()); } TEST_F(AmberScriptParserTest, BindBufferMissingDescriptorSetValue) { @@ -1084,48 +1028,6 @@ END)"; EXPECT_EQ("12: extra parameters after BIND command", r.Error()); } -TEST_F(AmberScriptParserTest, BindingBufferIdxExtraParams) { - std::string in = R"( -SHADER vertex my_shader PASSTHROUGH -SHADER fragment my_fragment GLSL -# GLSL Shader -END -BUFFER my_buf FORMAT R32G32B32A32_SFLOAT - -PIPELINE graphics my_pipeline - ATTACH my_shader - ATTACH my_fragment - - BIND BUFFER my_buf AS uniform DESCRIPTOR_SET 1 BINDING 2 IDX 5 EXTRA -END)"; - - Parser parser; - Result r = parser.Parse(in); - ASSERT_FALSE(r.IsSuccess()); - EXPECT_EQ("12: extra parameters after BIND command", r.Error()); -} - -TEST_F(AmberScriptParserTest, BindingBufferInvalidIdxValue) { - std::string in = R"( -SHADER vertex my_shader PASSTHROUGH -SHADER fragment my_fragment GLSL -# GLSL Shader -END -BUFFER my_buf FORMAT R32G32B32A32_SFLOAT - -PIPELINE graphics my_pipeline - ATTACH my_shader - ATTACH my_fragment - - BIND BUFFER my_buf AS uniform DESCRIPTOR_SET 1 BINDING 2 IDX INVALID -END)"; - - Parser parser; - Result r = parser.Parse(in); - ASSERT_FALSE(r.IsSuccess()); - EXPECT_EQ("12: invalid value for IDX in BIND command", r.Error()); -} - TEST_F(AmberScriptParserTest, BindingBufferInvalidBindingValue) { std::string in = R"( SHADER vertex my_shader PASSTHROUGH @@ -1180,7 +1082,7 @@ PIPELINE graphics my_pipeline ATTACH my_shader ATTACH my_fragment - BIND BUFFER my_buf AS INVALID DESCRIPTOR_SET 1 BINDING 2 IDX INVALID + BIND BUFFER my_buf AS INVALID DESCRIPTOR_SET 1 BINDING 2 END)"; Parser parser; diff --git a/src/amberscript/parser_buffer_test.cc b/src/amberscript/parser_buffer_test.cc index 0c0bbec..4f8769f 100644 --- a/src/amberscript/parser_buffer_test.cc +++ b/src/amberscript/parser_buffer_test.cc @@ -80,6 +80,34 @@ TEST_F(AmberScriptParserTest, BufferDataOneLine) { } } +TEST_F(AmberScriptParserTest, BufferDataFloat) { + std::string in = "BUFFER my_buffer DATA_TYPE float DATA 1 2 3 4 END"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& buffers = script->GetBuffers(); + ASSERT_EQ(1U, buffers.size()); + + ASSERT_TRUE(buffers[0] != nullptr); + EXPECT_EQ("my_buffer", buffers[0]->GetName()); + + ASSERT_TRUE(buffers[0]->IsDataBuffer()); + auto* buffer = buffers[0]->AsDataBuffer(); + EXPECT_TRUE(buffer->GetDatumType().IsFloat()); + EXPECT_EQ(4U, buffer->GetSize()); + EXPECT_EQ(4U * sizeof(float), buffer->GetSizeInBytes()); + + std::vector<float> results = {1, 2, 3, 4}; + const auto* data = buffer->GetValues<float>(); + ASSERT_EQ(results.size(), buffer->GetSize()); + for (size_t i = 0; i < results.size(); ++i) { + EXPECT_FLOAT_EQ(results[i], data[i]); + } +} + TEST_F(AmberScriptParserTest, BufferFill) { std::string in = "BUFFER my_buffer DATA_TYPE uint8 SIZE 5 FILL 5"; diff --git a/src/amberscript/parser_pipeline_test.cc b/src/amberscript/parser_pipeline_test.cc index 1610c58..41d781a 100644 --- a/src/amberscript/parser_pipeline_test.cc +++ b/src/amberscript/parser_pipeline_test.cc @@ -240,17 +240,29 @@ END)"; r.Error()); } -TEST_F(AmberScriptParserTest, PipelineDefaultDepthBuffer) { +TEST_F(AmberScriptParserTest, DerivePipeline) { std::string in = R"( SHADER vertex my_shader PASSTHROUGH SHADER fragment my_fragment GLSL # GLSL Shader END +SHADER fragment other_fragment GLSL +# GLSL Shader +END +BUFFER buf1 DATA_TYPE int32 SIZE 20 FILL 5 +BUFFER buf2 DATA_TYPE int32 SIZE 20 FILL 7 -PIPELINE graphics my_pipeline +PIPELINE graphics parent_pipeline ATTACH my_shader ATTACH my_fragment -END)"; + BIND BUFFER buf1 AS storage DESCRIPTOR_SET 1 BINDING 3 +END + +DERIVE_PIPELINE child_pipeline FROM parent_pipeline + ATTACH other_fragment + BIND BUFFER buf2 AS storage DESCRIPTOR_SET 1 BINDING 3 +END +)"; Parser parser; Result r = parser.Parse(in); @@ -258,17 +270,148 @@ END)"; auto script = parser.GetScript(); const auto& pipelines = script->GetPipelines(); - ASSERT_EQ(1U, pipelines.size()); + ASSERT_EQ(2U, pipelines.size()); - const auto* pipeline = pipelines[0].get(); - const auto& buf = pipeline->GetDepthBuffer(); - - ASSERT_TRUE(buf.buffer != nullptr); - EXPECT_EQ(FormatType::kD32_SFLOAT_S8_UINT, - buf.buffer->AsFormatBuffer()->GetFormat().GetFormatType()); - EXPECT_EQ(250 * 250, buf.buffer->GetSize()); - EXPECT_EQ(250 * 250 * (sizeof(float) + sizeof(uint8_t)), - buf.buffer->GetSizeInBytes()); + const auto* pipeline1 = pipelines[0].get(); + auto buffers1 = pipeline1->GetBuffers(); + ASSERT_EQ(1U, buffers1.size()); + EXPECT_EQ("buf1", buffers1[0].buffer->GetName()); + EXPECT_EQ(1, buffers1[0].descriptor_set); + EXPECT_EQ(3, buffers1[0].binding); + + auto shaders1 = pipeline1->GetShaders(); + ASSERT_EQ(2U, shaders1.size()); + EXPECT_EQ("my_shader", shaders1[0].GetShader()->GetName()); + EXPECT_EQ("my_fragment", shaders1[1].GetShader()->GetName()); + + const auto* pipeline2 = pipelines[1].get(); + EXPECT_EQ("child_pipeline", pipeline2->GetName()); + + auto buffers2 = pipeline2->GetBuffers(); + ASSERT_EQ(1U, buffers2.size()); + EXPECT_EQ("buf2", buffers2[0].buffer->GetName()); + EXPECT_EQ(1, buffers2[0].descriptor_set); + EXPECT_EQ(3, buffers2[0].binding); + + auto shaders2 = pipeline2->GetShaders(); + ASSERT_EQ(2U, shaders2.size()); + EXPECT_EQ("my_shader", shaders2[0].GetShader()->GetName()); + EXPECT_EQ("other_fragment", shaders2[1].GetShader()->GetName()); +} + +TEST_F(AmberScriptParserTest, DerivePipelineMissingEnd) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END + +PIPELINE graphics parent_pipeline + ATTACH my_shader + ATTACH my_fragment +END + +DERIVE_PIPELINE derived_pipeline FROM parent_pipeline +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("13: DERIVE_PIPELINE missing END command", r.Error()); +} + +TEST_F(AmberScriptParserTest, DerivePipelineMissingPipelineName) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END + +PIPELINE graphics parent_pipeline + ATTACH my_shader + ATTACH my_fragment +END + +DERIVE_PIPELINE FROM parent_pipeline +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("12: missing pipeline name for DERIVE_PIPELINE command", r.Error()); +} + +TEST_F(AmberScriptParserTest, DerivePipelineMissingFrom) { + std::string in = R"( +DERIVE_PIPELINE derived_pipeline parent_pipeline +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("2: missing FROM in DERIVE_PIPELINE command", r.Error()); +} + +TEST_F(AmberScriptParserTest, DerivePipelineMissingParentPipelineName) { + std::string in = R"( +DERIVE_PIPELINE derived_pipeline FROM +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("3: missing parent pipeline name in DERIVE_PIPELINE command", + r.Error()); +} + +TEST_F(AmberScriptParserTest, DerivePipelineUnknownParentPipeline) { + std::string in = R"( +DERIVE_PIPELINE derived_pipeline FROM parent_pipeline +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("2: unknown parent pipeline in DERIVE_PIPELINE command", r.Error()); +} + +TEST_F(AmberScriptParserTest, DerivePipelineDuplicatePipelineName) { + std::string in = R"( +SHADER vertex my_shader PASSTHROUGH +SHADER fragment my_fragment GLSL +# GLSL Shader +END + +PIPELINE graphics parent_pipeline + ATTACH my_shader + ATTACH my_fragment +END + +DERIVE_PIPELINE parent_pipeline FROM parent_pipeline +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("12: duplicate pipeline name for DERIVE_PIPELINE command", + r.Error()); +} + +TEST_F(AmberScriptParserTest, DerivePipelineNoParams) { + std::string in = R"( +DERIVE_PIPELINE +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("3: missing pipeline name for DERIVE_PIPELINE command", r.Error()); } } // namespace amberscript diff --git a/src/pipeline.cc b/src/pipeline.cc index a759aeb..7707dd2 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -31,7 +31,7 @@ const char* kDefaultDepthBufferFormat = "D32_SFLOAT_S8_UINT"; const char* Pipeline::kGeneratedColorBuffer = "framebuffer"; const char* Pipeline::kGeneratedDepthBuffer = "depth_buffer"; -Pipeline::ShaderInfo::ShaderInfo(const Shader* shader, ShaderType type) +Pipeline::ShaderInfo::ShaderInfo(Shader* shader, ShaderType type) : shader_(shader), shader_type_(type), entry_point_("main") {} Pipeline::ShaderInfo::ShaderInfo(const ShaderInfo&) = default; @@ -42,7 +42,20 @@ Pipeline::Pipeline(PipelineType type) : pipeline_type_(type) {} Pipeline::~Pipeline() = default; -Result Pipeline::AddShader(const Shader* shader, ShaderType shader_type) { +std::unique_ptr<Pipeline> Pipeline::Clone() const { + auto clone = MakeUnique<Pipeline>(pipeline_type_); + clone->shaders_ = shaders_; + clone->color_attachments_ = color_attachments_; + clone->vertex_buffers_ = vertex_buffers_; + clone->buffers_ = buffers_; + clone->depth_buffer_ = depth_buffer_; + clone->index_buffer_ = index_buffer_; + clone->fb_width_ = fb_width_; + clone->fb_height_ = fb_height_; + return clone; +} + +Result Pipeline::AddShader(Shader* shader, ShaderType shader_type) { if (!shader) return Result("shader can not be null when attached to pipeline"); @@ -55,12 +68,14 @@ Result Pipeline::AddShader(const Shader* shader, ShaderType shader_type) { return Result("can not add a compute shader to a graphics pipeline"); } - for (const auto& info : shaders_) { + for (auto& info : shaders_) { const auto* is = info.GetShader(); if (is == shader) return Result("can not add duplicate shader to pipeline"); - if (is->GetType() == shader_type) - return Result("can not add duplicate shader type to pipeline"); + if (is->GetType() == shader_type) { + info.SetShader(shader); + return {}; + } } shaders_.emplace_back(shader, shader_type); @@ -137,9 +152,7 @@ Result Pipeline::Validate() const { } } - if (depth_buffer_.buffer == nullptr) - return Result("PIPELINE missing depth buffer"); - if (depth_buffer_.buffer->GetSize() != fb_size) + if (depth_buffer_.buffer && depth_buffer_.buffer->GetSize() != fb_size) return Result("shared depth buffer must have same size over all PIPELINES"); if (pipeline_type_ == PipelineType::kGraphics) @@ -292,4 +305,22 @@ Buffer* Pipeline::GetBufferForBinding(uint32_t descriptor_set, return nullptr; } +void Pipeline::AddBuffer(Buffer* buf, + uint32_t descriptor_set, + uint32_t binding) { + // If this buffer binding already exists, overwrite with the new buffer. + for (auto& info : buffers_) { + if (info.descriptor_set == descriptor_set && info.binding == binding) { + info.buffer = buf; + return; + } + } + + buffers_.push_back(BufferInfo{buf}); + + auto& info = buffers_.back(); + info.descriptor_set = descriptor_set; + info.binding = binding; +} + } // namespace amber diff --git a/src/pipeline.h b/src/pipeline.h index 56bbd2a..cb6ded3 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -32,10 +32,12 @@ class Pipeline { public: class ShaderInfo { public: - ShaderInfo(const Shader*, ShaderType type); + ShaderInfo(Shader*, ShaderType type); ShaderInfo(const ShaderInfo&); ~ShaderInfo(); + ShaderInfo& operator=(const ShaderInfo&) = default; + void SetShaderOptimizations(const std::vector<std::string>& opts) { shader_optimizations_ = opts; } @@ -43,6 +45,7 @@ class Pipeline { return shader_optimizations_; } + void SetShader(Shader* shader) { shader_ = shader; } const Shader* GetShader() const { return shader_; } void SetEntryPoint(const std::string& ep) { entry_point_ = ep; } @@ -55,7 +58,7 @@ class Pipeline { void SetData(std::vector<uint32_t>&& data) { data_ = std::move(data); } private: - const Shader* shader_ = nullptr; + Shader* shader_ = nullptr; ShaderType shader_type_; std::vector<std::string> shader_optimizations_; std::string entry_point_; @@ -78,6 +81,8 @@ class Pipeline { explicit Pipeline(PipelineType type); ~Pipeline(); + std::unique_ptr<Pipeline> Clone() const; + bool IsGraphics() const { return pipeline_type_ == PipelineType::kGraphics; } bool IsCompute() const { return pipeline_type_ == PipelineType::kCompute; } PipelineType GetType() const { return pipeline_type_; } @@ -97,7 +102,7 @@ class Pipeline { } uint32_t GetFramebufferHeight() const { return fb_height_; } - Result AddShader(const Shader*, ShaderType); + Result AddShader(Shader*, ShaderType); std::vector<ShaderInfo>& GetShaders() { return shaders_; } const std::vector<ShaderInfo>& GetShaders() const { return shaders_; } @@ -123,17 +128,7 @@ class Pipeline { Result SetIndexBuffer(Buffer* buf); Buffer* GetIndexBuffer() const { return index_buffer_; } - void AddBuffer(Buffer* buf, - uint32_t descriptor_set, - uint32_t binding, - uint32_t location) { - buffers_.push_back(BufferInfo{buf}); - - auto& info = buffers_.back(); - info.descriptor_set = descriptor_set; - info.binding = binding; - info.location = location; - } + void AddBuffer(Buffer* buf, uint32_t descriptor_set, uint32_t binding); const std::vector<BufferInfo>& GetBuffers() const { return buffers_; } Buffer* GetBufferForBinding(uint32_t descriptor_set, uint32_t binding) const; diff --git a/src/pipeline_test.cc b/src/pipeline_test.cc index 0e6bb7b..bd61375 100644 --- a/src/pipeline_test.cc +++ b/src/pipeline_test.cc @@ -15,6 +15,7 @@ #include "src/pipeline.h" #include "gtest/gtest.h" +#include "src/make_unique.h" namespace amber { namespace { @@ -25,7 +26,7 @@ struct ShaderTypeData { } // namespace -class AmberScriptPipelineTest : public testing::Test { +class PipelineTest : public testing::Test { public: void TearDown() override { color_buffer_ = nullptr; @@ -51,7 +52,7 @@ class AmberScriptPipelineTest : public testing::Test { std::unique_ptr<Buffer> depth_buffer_; }; -TEST_F(AmberScriptPipelineTest, AddShader) { +TEST_F(PipelineTest, AddShader) { Shader v(kShaderTypeVertex); Shader f(kShaderTypeFragment); @@ -69,14 +70,14 @@ TEST_F(AmberScriptPipelineTest, AddShader) { EXPECT_EQ(&f, shaders[1].GetShader()); } -TEST_F(AmberScriptPipelineTest, MissingShader) { +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(AmberScriptPipelineTest, DuplicateShaders) { +TEST_F(PipelineTest, DuplicateShaders) { Shader v(kShaderTypeVertex); Shader f(kShaderTypeFragment); @@ -92,19 +93,6 @@ TEST_F(AmberScriptPipelineTest, DuplicateShaders) { EXPECT_EQ("can not add duplicate shader to pipeline", r.Error()); } -TEST_F(AmberScriptPipelineTest, DuplicateShaderType) { - Shader v(kShaderTypeVertex); - Shader f(kShaderTypeVertex); - - Pipeline p(PipelineType::kGraphics); - Result r = p.AddShader(&v, kShaderTypeVertex); - ASSERT_TRUE(r.IsSuccess()) << r.Error(); - - r = p.AddShader(&f, kShaderTypeVertex); - ASSERT_FALSE(r.IsSuccess()); - EXPECT_EQ("can not add duplicate shader type to pipeline", r.Error()); -} - using AmberScriptPipelineComputePipelineTest = testing::TestWithParam<ShaderTypeData>; TEST_P(AmberScriptPipelineComputePipelineTest, @@ -129,7 +117,7 @@ INSTANTIATE_TEST_CASE_P( ShaderTypeData{ kShaderTypeTessellationControl}), ); // NOLINT(whitespace/parens) -TEST_F(AmberScriptPipelineTest, SettingComputeShaderToGraphicsPipeline) { +TEST_F(PipelineTest, SettingComputeShaderToGraphicsPipeline) { Shader c(kShaderTypeCompute); Pipeline p(PipelineType::kGraphics); @@ -138,7 +126,7 @@ TEST_F(AmberScriptPipelineTest, SettingComputeShaderToGraphicsPipeline) { EXPECT_EQ("can not add a compute shader to a graphics pipeline", r.Error()); } -TEST_F(AmberScriptPipelineTest, SetShaderOptimizations) { +TEST_F(PipelineTest, SetShaderOptimizations) { Shader v(kShaderTypeVertex); Shader f(kShaderTypeFragment); @@ -164,7 +152,7 @@ TEST_F(AmberScriptPipelineTest, SetShaderOptimizations) { EXPECT_EQ(first, shaders[1].GetShaderOptimizations()); } -TEST_F(AmberScriptPipelineTest, DuplicateShaderOptimizations) { +TEST_F(PipelineTest, DuplicateShaderOptimizations) { Shader v(kShaderTypeVertex); Pipeline p(PipelineType::kGraphics); @@ -177,14 +165,14 @@ TEST_F(AmberScriptPipelineTest, DuplicateShaderOptimizations) { EXPECT_EQ("duplicate optimization flag (One) set on shader", r.Error()); } -TEST_F(AmberScriptPipelineTest, SetOptimizationForMissingShader) { +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(AmberScriptPipelineTest, SetOptimizationForInvalidShader) { +TEST_F(PipelineTest, SetOptimizationForInvalidShader) { Shader v(kShaderTypeVertex); v.SetName("my_shader"); @@ -194,7 +182,7 @@ TEST_F(AmberScriptPipelineTest, SetOptimizationForInvalidShader) { EXPECT_EQ("unknown shader specified for optimizations: my_shader", r.Error()); } -TEST_F(AmberScriptPipelineTest, GraphicsPipelineRequiresColorAttachment) { +TEST_F(PipelineTest, GraphicsPipelineRequiresColorAttachment) { Pipeline p(PipelineType::kGraphics); SetupDepthAttachment(&p); @@ -203,17 +191,7 @@ TEST_F(AmberScriptPipelineTest, GraphicsPipelineRequiresColorAttachment) { EXPECT_EQ("PIPELINE missing color attachment", r.Error()); } -TEST_F(AmberScriptPipelineTest, GraphicsPipelineRequiresDepthAttachment) { - Pipeline p(PipelineType::kGraphics); - SetupColorAttachment(&p, 0); - - Result r = p.Validate(); - ASSERT_FALSE(r.IsSuccess()); - EXPECT_EQ("PIPELINE missing depth buffer", r.Error()); -} - -TEST_F(AmberScriptPipelineTest, - GraphicsPipelineRequiresVertexAndFragmentShader) { +TEST_F(PipelineTest, GraphicsPipelineRequiresVertexAndFragmentShader) { Shader v(kShaderTypeVertex); Shader f(kShaderTypeFragment); Shader g(kShaderTypeGeometry); @@ -235,7 +213,7 @@ TEST_F(AmberScriptPipelineTest, EXPECT_TRUE(r.IsSuccess()) << r.Error(); } -TEST_F(AmberScriptPipelineTest, GraphicsPipelineMissingFragmentShader) { +TEST_F(PipelineTest, GraphicsPipelineMissingFragmentShader) { Shader v(kShaderTypeVertex); Shader g(kShaderTypeGeometry); @@ -254,7 +232,7 @@ TEST_F(AmberScriptPipelineTest, GraphicsPipelineMissingFragmentShader) { EXPECT_EQ("graphics pipeline requires a fragment shader", r.Error()); } -TEST_F(AmberScriptPipelineTest, GraphicsPipelineMissingVertexShader) { +TEST_F(PipelineTest, GraphicsPipelineMissingVertexShader) { Shader f(kShaderTypeFragment); Shader g(kShaderTypeGeometry); @@ -273,8 +251,7 @@ TEST_F(AmberScriptPipelineTest, GraphicsPipelineMissingVertexShader) { EXPECT_EQ("graphics pipeline requires a vertex shader", r.Error()); } -TEST_F(AmberScriptPipelineTest, - GraphicsPipelineMissingVertexAndFragmentShader) { +TEST_F(PipelineTest, GraphicsPipelineMissingVertexAndFragmentShader) { Shader g(kShaderTypeGeometry); Pipeline p(PipelineType::kGraphics); @@ -290,7 +267,7 @@ TEST_F(AmberScriptPipelineTest, r.Error()); } -TEST_F(AmberScriptPipelineTest, GraphicsPipelineWihoutShaders) { +TEST_F(PipelineTest, GraphicsPipelineWihoutShaders) { Pipeline p(PipelineType::kGraphics); SetupColorAttachment(&p, 0); SetupDepthAttachment(&p); @@ -301,7 +278,7 @@ TEST_F(AmberScriptPipelineTest, GraphicsPipelineWihoutShaders) { r.Error()); } -TEST_F(AmberScriptPipelineTest, ComputePipelineRequiresComputeShader) { +TEST_F(PipelineTest, ComputePipelineRequiresComputeShader) { Shader c(kShaderTypeCompute); Pipeline p(PipelineType::kCompute); @@ -315,7 +292,7 @@ TEST_F(AmberScriptPipelineTest, ComputePipelineRequiresComputeShader) { EXPECT_TRUE(r.IsSuccess()) << r.Error(); } -TEST_F(AmberScriptPipelineTest, ComputePipelineWithoutShader) { +TEST_F(PipelineTest, ComputePipelineWithoutShader) { Pipeline p(PipelineType::kCompute); SetupColorAttachment(&p, 0); SetupDepthAttachment(&p); @@ -325,7 +302,7 @@ TEST_F(AmberScriptPipelineTest, ComputePipelineWithoutShader) { EXPECT_EQ("compute pipeline requires a compute shader", r.Error()); } -TEST_F(AmberScriptPipelineTest, SetEntryPointForMissingShader) { +TEST_F(PipelineTest, SetEntryPointForMissingShader) { Shader c(kShaderTypeCompute); c.SetName("my_shader"); @@ -335,14 +312,14 @@ TEST_F(AmberScriptPipelineTest, SetEntryPointForMissingShader) { EXPECT_EQ("unknown shader specified for entry point: my_shader", r.Error()); } -TEST_F(AmberScriptPipelineTest, SetEntryPointForNullShader) { +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(AmberScriptPipelineTest, SetBlankEntryPoint) { +TEST_F(PipelineTest, SetBlankEntryPoint) { Shader c(kShaderTypeCompute); Pipeline p(PipelineType::kCompute); Result r = p.AddShader(&c, kShaderTypeCompute); @@ -353,7 +330,7 @@ TEST_F(AmberScriptPipelineTest, SetBlankEntryPoint) { EXPECT_EQ("entry point should not be blank", r.Error()); } -TEST_F(AmberScriptPipelineTest, ShaderDefaultEntryPoint) { +TEST_F(PipelineTest, ShaderDefaultEntryPoint) { Shader c(kShaderTypeCompute); Pipeline p(PipelineType::kCompute); Result r = p.AddShader(&c, kShaderTypeCompute); @@ -364,7 +341,7 @@ TEST_F(AmberScriptPipelineTest, ShaderDefaultEntryPoint) { EXPECT_EQ("main", shaders[0].GetEntryPoint()); } -TEST_F(AmberScriptPipelineTest, SetShaderEntryPoint) { +TEST_F(PipelineTest, SetShaderEntryPoint) { Shader c(kShaderTypeCompute); Pipeline p(PipelineType::kCompute); Result r = p.AddShader(&c, kShaderTypeCompute); @@ -378,7 +355,7 @@ TEST_F(AmberScriptPipelineTest, SetShaderEntryPoint) { EXPECT_EQ("my_main", shaders[0].GetEntryPoint()); } -TEST_F(AmberScriptPipelineTest, SetEntryPointMulitpleTimes) { +TEST_F(PipelineTest, SetEntryPointMulitpleTimes) { Shader c(kShaderTypeCompute); Pipeline p(PipelineType::kCompute); Result r = p.AddShader(&c, kShaderTypeCompute); @@ -392,4 +369,65 @@ TEST_F(AmberScriptPipelineTest, SetEntryPointMulitpleTimes) { 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<DataBuffer>(BufferType::kVertex); + vtex_buf->SetName("vertex_buffer"); + p.AddVertexBuffer(vtex_buf.get(), 1); + + auto idx_buf = MakeUnique<DataBuffer>(BufferType::kIndex); + idx_buf->SetName("Index Buffer"); + p.SetIndexBuffer(idx_buf.get()); + + auto buf1 = MakeUnique<DataBuffer>(BufferType::kStorage); + buf1->SetName("buf1"); + p.AddBuffer(buf1.get(), 1, 1); + + auto buf2 = MakeUnique<DataBuffer>(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); +} + } // namespace amber diff --git a/src/vkscript/command_parser.cc b/src/vkscript/command_parser.cc index d4f7625..e0b3292 100644 --- a/src/vkscript/command_parser.cc +++ b/src/vkscript/command_parser.cc @@ -595,7 +595,7 @@ Result CommandParser::ProcessSSBO() { b->SetName("AutoBuf-" + std::to_string(script_->GetBuffers().size())); buffer = b.get(); script_->AddBuffer(std::move(b)); - pipeline_->AddBuffer(buffer, set, binding, 0); + pipeline_->AddBuffer(buffer, set, binding); } cmd->SetBuffer(buffer); } @@ -727,7 +727,7 @@ Result CommandParser::ProcessUniform() { b->SetName("AutoBuf-" + std::to_string(script_->GetBuffers().size())); buffer = b.get(); script_->AddBuffer(std::move(b)); - pipeline_->AddBuffer(buffer, set, binding, 0); + pipeline_->AddBuffer(buffer, set, binding); } cmd->SetBuffer(buffer); } diff --git a/src/vkscript/parser.cc b/src/vkscript/parser.cc index deab09b..cda97d4 100644 --- a/src/vkscript/parser.cc +++ b/src/vkscript/parser.cc @@ -367,10 +367,11 @@ Result Parser::ProcessVertexDataBlock(const SectionParser::Section& section) { auto& value_data = values[j]; if (header.format->GetPackSize() > 0) { - if (!token->IsHex()) + if (!token->IsHex()) { return Result( make_error(tokenizer, "Invalid packed value in Vertex Data: " + token->ToOriginalString())); + } Value v; v.SetIntValue(token->AsHex()); @@ -379,9 +380,10 @@ Result Parser::ProcessVertexDataBlock(const SectionParser::Section& section) { auto& comps = header.format->GetComponents(); for (size_t i = 0; i < comps.size(); ++i, token = tokenizer.NextToken()) { - if (token->IsEOS() || token->IsEOL()) + if (token->IsEOS() || token->IsEOL()) { return Result(make_error(tokenizer, "Too few cells in given vertex data row")); + } auto& comp = comps[i]; diff --git a/src/vulkan/engine_vulkan.cc b/src/vulkan/engine_vulkan.cc index 64df5bb..dc10f01 100644 --- a/src/vulkan/engine_vulkan.cc +++ b/src/vulkan/engine_vulkan.cc @@ -212,7 +212,7 @@ Result EngineVulkan::CreatePipeline(amber::Pipeline* pipeline) { } for (const auto& buf_info : pipeline->GetBuffers()) { - BufferCommand::BufferType type = BufferCommand::BufferType::kSSBO; + auto type = BufferCommand::BufferType::kSSBO; if (buf_info.buffer->GetBufferType() == BufferType::kUniform) { type = BufferCommand::BufferType::kUniform; } else if (buf_info.buffer->GetBufferType() == BufferType::kPushConstant) { diff --git a/src/vulkan/graphics_pipeline.cc b/src/vulkan/graphics_pipeline.cc index 7536ee1..81b9bc9 100644 --- a/src/vulkan/graphics_pipeline.cc +++ b/src/vulkan/graphics_pipeline.cc @@ -785,6 +785,8 @@ Result GraphicsPipeline::ClearBuffer(const VkClearValue& clear_value, return cmd_buf_guard.GetResult(); frame_->ChangeFrameToWriteLayout(GetCommandBuffer()); + frame_->CopyBuffersToImages(); + frame_->TransferColorImagesToDevice(GetCommandBuffer()); { RenderPassGuard render_pass_guard(this); @@ -846,6 +848,8 @@ Result GraphicsPipeline::Draw(const DrawArraysCommand* command, return r; frame_->ChangeFrameToWriteLayout(GetCommandBuffer()); + frame_->CopyBuffersToImages(); + frame_->TransferColorImagesToDevice(GetCommandBuffer()); { RenderPassGuard render_pass_guard(this); diff --git a/tests/cases/draw_rectangles.amber b/tests/cases/draw_rectangles.amber new file mode 100644 index 0000000..9e2e3cb --- /dev/null +++ b/tests/cases/draw_rectangles.amber @@ -0,0 +1,80 @@ +#!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. + +DEVICE_FEATURE vertexPipelineStoresAndAtomics + +SHADER vertex vtex_shader GLSL +#version 430 + +layout(location = 0) in vec4 position; +layout(location = 0) out vec4 frag_color; + +layout(set = 0, binding = 0) buffer block1 { + vec4 in_color; +}; + +void main() { + gl_Position = position; + frag_color = in_color; +} +END + +SHADER fragment frag_shader GLSL +#version 430 + +layout(location = 0) in vec4 frag_color; +layout(location = 0) out vec4 final_color; + +void main() { + final_color = frag_color; +} +END + +BUFFER data_buf1 DATA_TYPE vec4<float> DATA 1 0 0 1 END +BUFFER data_buf2 DATA_TYPE vec4<float> DATA 0 1 0 1 END +BUFFER data_buf3 DATA_TYPE vec4<float> DATA 0 0 1 1 END +BUFFER data_buf4 DATA_TYPE vec4<float> DATA .5 0 .5 1 END + +BUFFER frame FORMAT R32G32B32A32_SFLOAT + +PIPELINE graphics pipeline1 + ATTACH vtex_shader + ATTACH frag_shader + + FRAMEBUFFER_SIZE 800 600 + BIND BUFFER frame AS color LOCATION 0 + BIND BUFFER data_buf1 AS storage DESCRIPTOR_SET 0 BINDING 0 +END +DERIVE_PIPELINE pipeline2 FROM pipeline1 + BIND BUFFER data_buf2 AS storage DESCRIPTOR_SET 0 BINDING 0 +END +DERIVE_PIPELINE pipeline3 FROM pipeline1 + BIND BUFFER data_buf3 AS storage DESCRIPTOR_SET 0 BINDING 0 +END +DERIVE_PIPELINE pipeline4 FROM pipeline1 + BIND BUFFER data_buf4 AS storage DESCRIPTOR_SET 0 BINDING 0 +END + +CLEAR pipeline1 +RUN pipeline1 DRAW_RECT POS 0 0 SIZE 400 300 +RUN pipeline2 DRAW_RECT POS 0 300 SIZE 400 300 +RUN pipeline3 DRAW_RECT POS 400 0 SIZE 400 300 +RUN pipeline4 DRAW_RECT POS 400 300 SIZE 400 300 + +EXPECT frame IDX 0 0 SIZE 400 300 EQ_RGBA 255 0 0 255 +EXPECT frame IDX 0 300 SIZE 400 300 EQ_RGBA 0 255 0 255 +EXPECT frame IDX 400 0 SIZE 400 300 EQ_RGBA 0 0 255 255 +EXPECT frame IDX 400 300 SIZE 400 300 EQ_RGBA 128 0 128 255 diff --git a/tools/amber-syntax.vim b/tools/amber-syntax.vim index e292611..3a6ba9a 100644 --- a/tools/amber-syntax.vim +++ b/tools/amber-syntax.vim @@ -36,7 +36,7 @@ syn keyword amberBlockCmd FRAMEBUFFER ENTRY_POINT SHADER_OPTIMIZATION syn keyword amberBlockCmd FORMAT FRAMEBUFFER_SIZE LOCATION BIND SAMPLER syn keyword amberBlockCmd VERTEX_DATA INDEX_DATA INDEXED IMAGE_ATTACHMENT syn keyword amberBlockCmd DEPTH_STENCIL_ATTACHMENT DEVICE_FEATURE TOLERANCE -syn keyword amberBlockCmd REPEAT COPY +syn keyword amberBlockCmd REPEAT COPY DERIVE_PIPELINE FROM syn keyword amberComparator EQ NE LT LE GT GE EQ_RGB EQ_RGBA diff --git a/tools/amber.sublime-syntax b/tools/amber.sublime-syntax index 9aee90a..4a9ad3a 100644 --- a/tools/amber.sublime-syntax +++ b/tools/amber.sublime-syntax @@ -27,7 +27,9 @@ contexts: scope: keyword.control.amber - match: '\b(FORMAT|FRAMEBUFFER_SIZE|BIND|SAMPLER|VERTEX_DATA|INDEX_DATA|INDEXED)\b' scope: keyword.control.amber - - match : '\b(IMAGE_ATTACHMENT|DEPTH_STENCIL_ATTACHMENT|LOCATION|DEVICE_FEATURE)\b' + - match: '\b(IMAGE_ATTACHMENT|DEPTH_STENCIL_ATTACHMENT|LOCATION|DEVICE_FEATURE)\b' + scope: keyword.control.amber + - match: '\b(DERIVE_PIPELINE|FROM)\b' scope: keyword.control.amber - match : '\b(COPY|TOLERANCE|REPEAT)\b' scope: keyword.control.amber |