diff options
-rw-r--r-- | docs/amber_script.md | 18 | ||||
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/amberscript/parser.cc | 102 | ||||
-rw-r--r-- | src/amberscript/parser.h | 4 | ||||
-rw-r--r-- | src/amberscript/parser_repeat_test.cc | 163 | ||||
-rw-r--r-- | src/command.cc | 9 | ||||
-rw-r--r-- | src/command.h | 35 | ||||
-rw-r--r-- | src/executor.cc | 121 | ||||
-rw-r--r-- | src/executor.h | 1 | ||||
-rw-r--r-- | src/script.h | 5 | ||||
-rw-r--r-- | src/vkscript/command_parser.cc | 8 | ||||
-rw-r--r-- | src/vulkan/engine_vulkan.cc | 28 | ||||
-rw-r--r-- | src/vulkan/pipeline.cc | 16 | ||||
-rw-r--r-- | src/vulkan/pipeline.h | 6 | ||||
-rw-r--r-- | tests/cases/repeat.amber | 36 | ||||
-rw-r--r-- | tools/amber-syntax.vim | 3 | ||||
-rw-r--r-- | tools/amber.sublime-syntax | 2 |
17 files changed, 462 insertions, 96 deletions
diff --git a/docs/amber_script.md b/docs/amber_script.md index 02cd177..c7d1399 100644 --- a/docs/amber_script.md +++ b/docs/amber_script.md @@ -313,6 +313,24 @@ RUN <pipeline_name> DRAW_ARRAY INDEXED AS <topology> \ START_IDX <value> COUNT <count_value> ``` +### Repeating commands + +It is sometimes useful to run a given draw command multiple times. This can be +to detect deterministic rendering or other features. + +``` +REPEAT <count> +<command>+ +END +``` + +The commands which can be used inside a `REPEAT` block are: + * `CLEAR` + * `CLEAR_COLOR` + * `COPY` + * `EXPECT` + * `RUN` + ### Commands ``` # Sets the clear color to use for |pipeline| which must be a `graphics` diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5940605..9906d07 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -87,6 +87,7 @@ if (${AMBER_ENABLE_TESTS}) amberscript/parser_expect_test.cc amberscript/parser_framebuffer_test.cc amberscript/parser_pipeline_test.cc + amberscript/parser_repeat_test.cc amberscript/parser_run_test.cc amberscript/parser_shader_opt_test.cc amberscript/parser_shader_test.cc diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc index 60d431f..c0fa6c9 100644 --- a/src/amberscript/parser.cc +++ b/src/amberscript/parser.cc @@ -72,22 +72,16 @@ Result Parser::Parse(const std::string& data) { Result r; std::string tok = token->AsString(); - if (tok == "BUFFER") { + if (IsRepeatable(tok)) { + r = ParseRepeatableCommand(tok); + } else if (tok == "BUFFER") { r = ParseBuffer(); - } else if (tok == "CLEAR") { - r = ParseClear(); - } else if (tok == "CLEAR_COLOR") { - r = ParseClearColor(); - } else if (tok == "COPY") { - r = ParseCopy(); } else if (tok == "DEVICE_FEATURE") { r = ParseDeviceFeature(); - } else if (tok == "EXPECT") { - r = ParseExpect(); } else if (tok == "PIPELINE") { r = ParsePipelineBlock(); - } else if (tok == "RUN") { - r = ParseRun(); + } else if (tok == "REPEAT") { + r = ParseRepeat(); } else if (tok == "SHADER") { r = ParseShaderBlock(); } else { @@ -96,6 +90,7 @@ Result Parser::Parse(const std::string& data) { if (!r.IsSuccess()) return Result(make_error(r.Error())); } + script_->SetCommands(std::move(command_list_)); // Generate any needed color and depth attachments. This is done before // validating in case one of the pipelines specifies the framebuffer size @@ -146,6 +141,28 @@ Result Parser::Parse(const std::string& data) { return {}; } +bool Parser::IsRepeatable(const std::string& name) const { + return name == "CLEAR" || name == "CLEAR_COLOR" || name == "COPY" || + name == "EXPECT" || name == "RUN"; +} + +// The given |name| must be one of the repeatable commands or this method +// returns an error result. +Result Parser::ParseRepeatableCommand(const std::string& name) { + if (name == "CLEAR") + return ParseClear(); + if (name == "CLEAR_COLOR") + return ParseClearColor(); + if (name == "COPY") + return ParseCopy(); + if (name == "EXPECT") + return ParseExpect(); + if (name == "RUN") + return ParseRun(); + + return Result("invalid repeatable command: " + name); +} + Result Parser::ToShaderType(const std::string& str, ShaderType* type) { assert(type); @@ -922,7 +939,7 @@ Result Parser::ParseRun() { } cmd->SetZ(token->AsUint32()); - script_->AddCommand(std::move(cmd)); + command_list_.push_back(std::move(cmd)); return ValidateEndOfStatement("RUN command"); } if (!token->IsString()) @@ -986,7 +1003,7 @@ Result Parser::ParseRun() { return r; cmd->SetHeight(token->AsFloat()); - script_->AddCommand(std::move(cmd)); + command_list_.push_back(std::move(cmd)); return ValidateEndOfStatement("RUN command"); } @@ -996,7 +1013,7 @@ Result Parser::ParseRun() { auto cmd = MakeUnique<DrawArraysCommand>(pipeline, PipelineData{}); - script_->AddCommand(std::move(cmd)); + command_list_.push_back(std::move(cmd)); return ValidateEndOfStatement("RUN command"); } @@ -1016,7 +1033,7 @@ Result Parser::ParseClear() { return Result("CLEAR command requires graphics pipeline"); auto cmd = MakeUnique<ClearCommand>(pipeline); - script_->AddCommand(std::move(cmd)); + command_list_.push_back(std::move(cmd)); return ValidateEndOfStatement("CLEAR command"); } @@ -1103,7 +1120,7 @@ Result Parser::ParseExpect() { } auto cmd = MakeUnique<CompareBufferCommand>(buffer, buffer_2); - script_->AddCommand(std::move(cmd)); + command_list_.push_back(std::move(cmd)); // Early return return ValidateEndOfStatement("EXPECT EQ_BUFFER command"); @@ -1192,7 +1209,7 @@ Result Parser::ParseExpect() { probe->SetA(token->AsFloat() / 255.f); } - script_->AddCommand(std::move(probe)); + command_list_.push_back(std::move(probe)); } else if (token->IsString() && IsComparator(token->AsString())) { if (has_y_val) return Result("Y value not needed for non-color comparator"); @@ -1213,7 +1230,7 @@ Result Parser::ParseExpect() { if (values.empty()) return Result("missing comparison values for EXPECT command"); probe->SetValues(std::move(values)); - script_->AddCommand(std::move(probe)); + command_list_.push_back(std::move(probe)); return {}; } else { return Result("unexpected token in EXPECT command: " + @@ -1273,7 +1290,7 @@ Result Parser::ParseCopy() { return Result("COPY origin and destination buffers are identical"); auto cmd = MakeUnique<CopyCommand>(buffer_from, buffer_to); - script_->AddCommand(std::move(cmd)); + command_list_.push_back(std::move(cmd)); return ValidateEndOfStatement("COPY command"); } @@ -1334,7 +1351,7 @@ Result Parser::ParseClearColor() { token->ConvertToDouble(); cmd->SetA(token->AsFloat() / 255.f); - script_->AddCommand(std::move(cmd)); + command_list_.push_back(std::move(cmd)); return ValidateEndOfStatement("CLEAR_COLOR command"); } @@ -1352,5 +1369,50 @@ Result Parser::ParseDeviceFeature() { return ValidateEndOfStatement("DEVICE_FEATURE command"); } +Result Parser::ParseRepeat() { + auto token = tokenizer_->NextToken(); + if (token->IsEOL() || token->IsEOL()) + return Result("missing count parameter for REPEAT command"); + if (!token->IsInteger()) { + return Result("invalid count parameter for REPEAT command: " + + token->ToOriginalString()); + } + if (token->AsInt32() <= 0) + return Result("count parameter must be > 0 for REPEAT command"); + + uint32_t count = token->AsUint32(); + + std::vector<std::unique_ptr<Command>> cur_commands; + std::swap(cur_commands, command_list_); + + for (token = tokenizer_->NextToken(); !token->IsEOS(); + token = tokenizer_->NextToken()) { + if (token->IsEOL()) + continue; + if (!token->IsString()) + return Result("expected string"); + + std::string tok = token->AsString(); + if (tok == "END") + break; + if (!IsRepeatable(tok)) + return Result("unknown token: " + tok); + + Result r = ParseRepeatableCommand(tok); + if (!r.IsSuccess()) + return r; + } + if (!token->IsString() || token->AsString() != "END") + return Result("missing END for REPEAT command"); + + auto cmd = MakeUnique<RepeatCommand>(count); + cmd->SetCommands(std::move(command_list_)); + + std::swap(cur_commands, command_list_); + command_list_.push_back(std::move(cmd)); + + return ValidateEndOfStatement("REPEAT command"); +} + } // namespace amberscript } // namespace amber diff --git a/src/amberscript/parser.h b/src/amberscript/parser.h index 205e18b..faf25f2 100644 --- a/src/amberscript/parser.h +++ b/src/amberscript/parser.h @@ -67,6 +67,9 @@ class Parser : public amber::Parser { Result ParseExpect(); Result ParseCopy(); Result ParseDeviceFeature(); + Result ParseRepeat(); + bool IsRepeatable(const std::string& name) const; + Result ParseRepeatableCommand(const std::string& name); // 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 @@ -77,6 +80,7 @@ class Parser : public amber::Parser { std::vector<Value>* values); std::unique_ptr<Tokenizer> tokenizer_; + std::vector<std::unique_ptr<Command>> command_list_; }; } // namespace amberscript diff --git a/src/amberscript/parser_repeat_test.cc b/src/amberscript/parser_repeat_test.cc new file mode 100644 index 0000000..3cf2ed7 --- /dev/null +++ b/src/amberscript/parser_repeat_test.cc @@ -0,0 +1,163 @@ +// Copyright 2019 The Amber Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or parseried. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" +#include "src/amberscript/parser.h" + +namespace amber { +namespace amberscript { + +using AmberScriptParserTest = testing::Test; + +TEST_F(AmberScriptParserTest, Repeat) { + std::string in = R"( +SHADER compute shader GLSL +# shader +END + +PIPELINE compute my_pipeline + ATTACH shader +END + +REPEAT 4 + RUN my_pipeline 1 2 3 + RUN my_pipeline 4 5 6 + RUN my_pipeline 7 8 9 +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& commands = script->GetCommands(); + ASSERT_EQ(1U, commands.size()); + + auto* cmd = commands[0].get(); + ASSERT_TRUE(cmd->IsRepeat()); + + auto* repeat = cmd->AsRepeat(); + EXPECT_EQ(4U, repeat->GetCount()); + + const auto& repeat_cmds = repeat->GetCommands(); + ASSERT_EQ(3U, repeat_cmds.size()); + ASSERT_TRUE(repeat_cmds[0]->IsCompute()); + EXPECT_EQ(1U, repeat_cmds[0]->AsCompute()->GetX()); + ASSERT_TRUE(repeat_cmds[1]->IsCompute()); + EXPECT_EQ(4U, repeat_cmds[1]->AsCompute()->GetX()); + ASSERT_TRUE(repeat_cmds[2]->IsCompute()); + EXPECT_EQ(7U, repeat_cmds[2]->AsCompute()->GetX()); +} + +TEST_F(AmberScriptParserTest, RepeatMissingNum) { + std::string in = R"( +REPEAT + RUN my_pipeline 1 1 1 +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("3: missing count parameter for REPEAT command", r.Error()); +} + +TEST_F(AmberScriptParserTest, RepeatInvalidNum) { + std::string in = R"( +REPEAT INVALID + RUN my_pipeline 1 1 1 +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("2: invalid count parameter for REPEAT command: INVALID", + r.Error()); +} + +TEST_F(AmberScriptParserTest, RepeatFloatNum) { + std::string in = R"( +REPEAT 3.4 + RUN my_pipeline 1 1 1 +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("2: invalid count parameter for REPEAT command: 3.4", r.Error()); +} + +TEST_F(AmberScriptParserTest, RepeatMissingEnd) { + std::string in = R"( +SHADER compute shader GLSL +# shader +END + +PIPELINE compute my_pipeline + ATTACH shader +END +REPEAT 3 + RUN my_pipeline 1 1 1 +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("11: missing END for REPEAT command", r.Error()); +} + +TEST_F(AmberScriptParserTest, RepeatExtraParams) { + std::string in = R"( +REPEAT 3 EXTRA + RUN my_pipeline 1 1 1 +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("2: unknown token: EXTRA", r.Error()); +} + +TEST_F(AmberScriptParserTest, RepeatNegativeCount) { + std::string in = R"( +REPEAT -3 + RUN my_pipeline 1 1 1 +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("2: count parameter must be > 0 for REPEAT command", r.Error()); +} + +TEST_F(AmberScriptParserTest, RepeatZeroCount) { + std::string in = R"( +REPEAT 0 + RUN my_pipeline 1 1 1 +END +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("2: count parameter must be > 0 for REPEAT command", r.Error()); +} + +} // namespace amberscript +} // namespace amber diff --git a/src/command.cc b/src/command.cc index ee5cac4..84db7fe 100644 --- a/src/command.cc +++ b/src/command.cc @@ -78,6 +78,10 @@ ProbeSSBOCommand* Command::AsProbeSSBO() { return static_cast<ProbeSSBOCommand*>(this); } +RepeatCommand* Command::AsRepeat() { + return static_cast<RepeatCommand*>(this); +} + PipelineCommand::PipelineCommand(Type type, Pipeline* pipeline) : Command(type), pipeline_(pipeline) {} @@ -156,4 +160,9 @@ EntryPointCommand::EntryPointCommand(Pipeline* pipeline) EntryPointCommand::~EntryPointCommand() = default; +RepeatCommand::RepeatCommand(uint32_t count) + : Command(Type::kRepeat), count_(count) {} + +RepeatCommand::~RepeatCommand() = default; + } // namespace amber diff --git a/src/command.h b/src/command.h index 2492f51..0b7e894 100644 --- a/src/command.h +++ b/src/command.h @@ -16,6 +16,7 @@ #define SRC_COMMAND_H_ #include <cstdint> +#include <memory> #include <string> #include <utility> #include <vector> @@ -29,8 +30,9 @@ namespace amber { -class ClearCommand; +class BufferCommand; class ClearColorCommand; +class ClearCommand; class ClearDepthCommand; class ClearStencilCommand; class CompareBufferCommand; @@ -43,7 +45,7 @@ class PatchParameterVerticesCommand; class Pipeline; class ProbeCommand; class ProbeSSBOCommand; -class BufferCommand; +class RepeatCommand; class Command { public: @@ -62,11 +64,14 @@ class Command { kPipelineProperties, kProbe, kProbeSSBO, - kBuffer + kBuffer, + kRepeat }; virtual ~Command(); + Command::Type GetType() const { return command_type_; } + bool IsDrawRect() const { return command_type_ == Type::kDrawRect; } bool IsDrawArrays() const { return command_type_ == Type::kDrawArrays; } bool IsCompareBuffer() const { return command_type_ == Type::kCompareBuffer; } @@ -83,6 +88,7 @@ class Command { return command_type_ == Type::kPatchParameterVertices; } bool IsEntryPoint() const { return command_type_ == Type::kEntryPoint; } + bool IsRepeat() { return command_type_ == Type::kRepeat; } ClearCommand* AsClear(); ClearColorCommand* AsClearColor(); @@ -98,6 +104,7 @@ class Command { ProbeCommand* AsProbe(); ProbeSSBOCommand* AsProbeSSBO(); BufferCommand* AsBuffer(); + RepeatCommand* AsRepeat(); void SetLine(size_t line) { line_ = line; } size_t GetLine() const { return line_; } @@ -508,6 +515,28 @@ class EntryPointCommand : public PipelineCommand { std::string entry_point_name_; }; +class RepeatCommand : public Command { + public: + explicit RepeatCommand(uint32_t count); + ~RepeatCommand() override; + + uint32_t GetCount() const { return count_; } + + /// Sets |cmds| to the list of commands to execute against the engine. + void SetCommands(std::vector<std::unique_ptr<Command>> cmds) { + commands_ = std::move(cmds); + } + + /// Retrieves the list of commands to execute against the engine. + const std::vector<std::unique_ptr<Command>>& GetCommands() const { + return commands_; + } + + private: + uint32_t count_ = 0; + std::vector<std::unique_ptr<Command>> commands_; +}; + } // namespace amber #endif // SRC_COMMAND_H_ diff --git a/src/executor.cc b/src/executor.cc index d65b285..fc9c70c 100644 --- a/src/executor.cc +++ b/src/executor.cc @@ -70,63 +70,78 @@ Result Executor::Execute(Engine* engine, // Process Commands for (const auto& cmd : script->GetCommands()) { - Result r; - if (cmd->IsProbe()) { - assert(cmd->AsProbe()->GetBuffer()->IsFormatBuffer()); - - auto* buffer = cmd->AsProbe()->GetBuffer()->AsFormatBuffer(); - assert(buffer); - - r = verifier_.Probe(cmd->AsProbe(), &buffer->GetFormat(), - buffer->GetTexelStride(), buffer->GetRowStride(), - buffer->GetWidth(), buffer->GetHeight(), - buffer->ValuePtr()->data()); - } else if (cmd->IsProbeSSBO()) { - auto probe_ssbo = cmd->AsProbeSSBO(); - - const auto* buffer = cmd->AsProbe()->GetBuffer(); - assert(buffer); - - r = verifier_.ProbeSSBO(probe_ssbo, buffer->GetSize(), - buffer->ValuePtr()->data()); - } else if (cmd->IsClear()) { - r = engine->DoClear(cmd->AsClear()); - } else if (cmd->IsClearColor()) { - r = engine->DoClearColor(cmd->AsClearColor()); - } else if (cmd->IsClearDepth()) { - r = engine->DoClearDepth(cmd->AsClearDepth()); - } else if (cmd->IsClearStencil()) { - r = engine->DoClearStencil(cmd->AsClearStencil()); - } else if (cmd->IsCompareBuffer()) { - auto compare = cmd->AsCompareBuffer(); - auto buffer_1 = compare->GetBuffer1(); - auto buffer_2 = compare->GetBuffer2(); - r = buffer_1->IsEqual(buffer_2); - } else if (cmd->IsCopy()) { - auto copy = cmd->AsCopy(); - auto buffer_from = copy->GetBufferFrom(); - auto buffer_to = copy->GetBufferTo(); - r = buffer_from->CopyTo(buffer_to); - } else if (cmd->IsDrawRect()) { - r = engine->DoDrawRect(cmd->AsDrawRect()); - } else if (cmd->IsDrawArrays()) { - r = engine->DoDrawArrays(cmd->AsDrawArrays()); - } else if (cmd->IsCompute()) { - r = engine->DoCompute(cmd->AsCompute()); - } else if (cmd->IsEntryPoint()) { - r = engine->DoEntryPoint(cmd->AsEntryPoint()); - } else if (cmd->IsPatchParameterVertices()) { - r = engine->DoPatchParameterVertices(cmd->AsPatchParameterVertices()); - } else if (cmd->IsBuffer()) { - r = engine->DoBuffer(cmd->AsBuffer()); - } else { - return Result("Unknown command type"); - } - + Result r = ExecuteCommand(engine, cmd.get()); if (!r.IsSuccess()) return r; } return {}; } +Result Executor::ExecuteCommand(Engine* engine, Command* cmd) { + if (cmd->IsProbe()) { + assert(cmd->AsProbe()->GetBuffer()->IsFormatBuffer()); + + auto* buffer = cmd->AsProbe()->GetBuffer()->AsFormatBuffer(); + assert(buffer); + + return verifier_.Probe(cmd->AsProbe(), &buffer->GetFormat(), + buffer->GetTexelStride(), buffer->GetRowStride(), + buffer->GetWidth(), buffer->GetHeight(), + buffer->ValuePtr()->data()); + } + if (cmd->IsProbeSSBO()) { + auto probe_ssbo = cmd->AsProbeSSBO(); + + const auto* buffer = cmd->AsProbe()->GetBuffer(); + assert(buffer); + + return verifier_.ProbeSSBO(probe_ssbo, buffer->GetSize(), + buffer->ValuePtr()->data()); + } + if (cmd->IsClear()) + return engine->DoClear(cmd->AsClear()); + if (cmd->IsClearColor()) + return engine->DoClearColor(cmd->AsClearColor()); + if (cmd->IsClearDepth()) + return engine->DoClearDepth(cmd->AsClearDepth()); + if (cmd->IsClearStencil()) + return engine->DoClearStencil(cmd->AsClearStencil()); + if (cmd->IsCompareBuffer()) { + auto compare = cmd->AsCompareBuffer(); + auto buffer_1 = compare->GetBuffer1(); + auto buffer_2 = compare->GetBuffer2(); + return buffer_1->IsEqual(buffer_2); + } + if (cmd->IsCopy()) { + auto copy = cmd->AsCopy(); + auto buffer_from = copy->GetBufferFrom(); + auto buffer_to = copy->GetBufferTo(); + return buffer_from->CopyTo(buffer_to); + } + if (cmd->IsDrawRect()) + return engine->DoDrawRect(cmd->AsDrawRect()); + if (cmd->IsDrawArrays()) + return engine->DoDrawArrays(cmd->AsDrawArrays()); + if (cmd->IsCompute()) + return engine->DoCompute(cmd->AsCompute()); + if (cmd->IsEntryPoint()) + return engine->DoEntryPoint(cmd->AsEntryPoint()); + if (cmd->IsPatchParameterVertices()) + return engine->DoPatchParameterVertices(cmd->AsPatchParameterVertices()); + if (cmd->IsBuffer()) + return engine->DoBuffer(cmd->AsBuffer()); + if (cmd->IsRepeat()) { + for (uint32_t i = 0; i < cmd->AsRepeat()->GetCount(); ++i) { + for (const auto& sub_cmd : cmd->AsRepeat()->GetCommands()) { + Result r = ExecuteCommand(engine, sub_cmd.get()); + if (!r.IsSuccess()) + return r; + } + } + return {}; + } + return Result("Unknown command type: " + + std::to_string(static_cast<uint32_t>(cmd->GetType()))); +} + } // namespace amber diff --git a/src/executor.h b/src/executor.h index 8c57503..8224c8f 100644 --- a/src/executor.h +++ b/src/executor.h @@ -41,6 +41,7 @@ class Executor { private: Result CompileShaders(const Script* script, const ShaderMap& shader_map); + Result ExecuteCommand(Engine* engine, Command* cmd); Verifier verifier_; }; diff --git a/src/script.h b/src/script.h index 5aad06a..ae3ef33 100644 --- a/src/script.h +++ b/src/script.h @@ -143,11 +143,6 @@ class Script : public RecipeImpl { commands_ = std::move(cmds); } - /// Appends |cmd| to the end of the list of commands to execute. - void AddCommand(std::unique_ptr<Command> cmd) { - commands_.push_back(std::move(cmd)); - } - /// Retrieves the list of commands to execute against the engine. const std::vector<std::unique_ptr<Command>>& GetCommands() const { return commands_; diff --git a/src/vkscript/command_parser.cc b/src/vkscript/command_parser.cc index 0fd2c69..d4f7625 100644 --- a/src/vkscript/command_parser.cc +++ b/src/vkscript/command_parser.cc @@ -647,7 +647,13 @@ Result CommandParser::ProcessSSBO() { return Result("Invalid size value for ssbo command: " + token->ToOriginalString()); - cmd->SetSize(token->AsUint32()); + uint32_t size = token->AsUint32(); + cmd->SetSize(size); + + // Resize the buffer so we'll correctly create the descriptor sets. + auto* buf = cmd->GetBuffer(); + buf->SetSize(size); + buf->ValuePtr()->resize(size); token = tokenizer_->NextToken(); if (!token->IsEOS() && !token->IsEOL()) diff --git a/src/vulkan/engine_vulkan.cc b/src/vulkan/engine_vulkan.cc index 268a6fe..64df5bb 100644 --- a/src/vulkan/engine_vulkan.cc +++ b/src/vulkan/engine_vulkan.cc @@ -211,6 +211,29 @@ Result EngineVulkan::CreatePipeline(amber::Pipeline* pipeline) { info.vk_pipeline->AsGraphics()->SetIndexBuffer(buf); } + for (const auto& buf_info : pipeline->GetBuffers()) { + BufferCommand::BufferType type = BufferCommand::BufferType::kSSBO; + if (buf_info.buffer->GetBufferType() == BufferType::kUniform) { + type = BufferCommand::BufferType::kUniform; + } else if (buf_info.buffer->GetBufferType() == BufferType::kPushConstant) { + type = BufferCommand::BufferType::kPushConstant; + } else if (buf_info.buffer->GetBufferType() != BufferType::kStorage) { + return Result("Vulkan: CreatePipeline - unknown buffer type: " + + std::to_string(static_cast<uint32_t>( + buf_info.buffer->GetBufferType()))); + } + + auto cmd = MakeUnique<BufferCommand>(type, pipeline); + cmd->SetDescriptorSet(buf_info.descriptor_set); + cmd->SetBinding(buf_info.binding); + cmd->SetBuffer(buf_info.buffer); + cmd->SetDatumType(buf_info.buffer->AsDataBuffer()->GetDatumType()); + + r = info.vk_pipeline->AddDescriptor(cmd.get()); + if (!r.IsSuccess()) + return r; + } + return {}; } @@ -406,15 +429,12 @@ Result EngineVulkan::DoPatchParameterVertices( } Result EngineVulkan::DoBuffer(const BufferCommand* cmd) { - auto& info = pipeline_map_[cmd->GetPipeline()]; - if (cmd->IsPushConstant()) - return info.vk_pipeline->AddPushConstant(cmd); - if (!device_->IsDescriptorSetInBounds(cmd->GetDescriptorSet())) { return Result( "Vulkan::DoBuffer exceed maxBoundDescriptorSets limit of physical " "device"); } + auto& info = pipeline_map_[cmd->GetPipeline()]; return info.vk_pipeline->AddDescriptor(cmd); } diff --git a/src/vulkan/pipeline.cc b/src/vulkan/pipeline.cc index faab16c..9fbd245 100644 --- a/src/vulkan/pipeline.cc +++ b/src/vulkan/pipeline.cc @@ -244,6 +244,8 @@ Result Pipeline::AddPushConstant(const BufferCommand* command) { Result Pipeline::AddDescriptor(const BufferCommand* cmd) { if (cmd == nullptr) return Result("Pipeline::AddDescriptor BufferCommand is nullptr"); + if (cmd->IsPushConstant()) + return AddPushConstant(cmd); if (!cmd->IsSSBO() && !cmd->IsUniform()) return Result("Pipeline::AddDescriptor not supported buffer type"); @@ -296,12 +298,14 @@ Result Pipeline::AddDescriptor(const BufferCommand* cmd) { "and binding"); } - auto* buf_desc = static_cast<BufferDescriptor*>(desc); - Result r = - buf_desc->AddToBuffer(cmd->GetDatumType().GetType(), cmd->GetOffset(), - cmd->GetSize(), cmd->GetValues()); - if (!r.IsSuccess()) - return r; + if (!cmd->GetValues().empty()) { + auto* buf_desc = static_cast<BufferDescriptor*>(desc); + Result r = + buf_desc->AddToBuffer(cmd->GetDatumType().GetType(), cmd->GetOffset(), + cmd->GetSize(), cmd->GetValues()); + if (!r.IsSuccess()) + return r; + } return {}; } diff --git a/src/vulkan/pipeline.h b/src/vulkan/pipeline.h index 5daaf10..73d83e2 100644 --- a/src/vulkan/pipeline.h +++ b/src/vulkan/pipeline.h @@ -54,9 +54,6 @@ class Pipeline { // buffer data object and put it into buffer data queue in host. Result ReadbackDescriptorsToHostDataQueue(); - // Add information of how and what to do with push constant. - Result AddPushConstant(const BufferCommand* command); - void SetEntryPointName(VkShaderStageFlagBits stage, const std::string& entry) { entry_points_[stage] = entry; @@ -114,6 +111,9 @@ class Pipeline { Result CreateDescriptorPools(); Result CreateDescriptorSets(); + // Add information of how and what to do with push constant. + Result AddPushConstant(const BufferCommand* command); + PipelineType pipeline_type_; std::vector<DescriptorSetInfo> descriptor_set_info_; std::vector<VkPipelineShaderStageCreateInfo> shader_stage_info_; diff --git a/tests/cases/repeat.amber b/tests/cases/repeat.amber new file mode 100644 index 0000000..a3a804b --- /dev/null +++ b/tests/cases/repeat.amber @@ -0,0 +1,36 @@ +#!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. + +SHADER compute shader GLSL +#version 430 +layout(set = 0, binding = 0) buffer block1 { + int val; +}; + +void main() { + val = val + 1; +} +END +BUFFER buf DATA_TYPE int32 DATA 0 END + +PIPELINE compute my_pipeline + ATTACH shader + BIND BUFFER buf AS storage DESCRIPTOR_SET 0 BINDING 0 +END + +REPEAT 4 + RUN my_pipeline 1 1 1 +END +EXPECT buf IDX 0 EQ 4 diff --git a/tools/amber-syntax.vim b/tools/amber-syntax.vim index 540d923..e292611 100644 --- a/tools/amber-syntax.vim +++ b/tools/amber-syntax.vim @@ -35,7 +35,8 @@ syn keyword amberBlockCmd COUNT CLEAR CLEAR_COLOR AS POS DRAW_RECT INC_BY 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 +syn keyword amberBlockCmd DEPTH_STENCIL_ATTACHMENT DEVICE_FEATURE TOLERANCE +syn keyword amberBlockCmd REPEAT COPY 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 acf685f..9aee90a 100644 --- a/tools/amber.sublime-syntax +++ b/tools/amber.sublime-syntax @@ -29,6 +29,8 @@ contexts: scope: keyword.control.amber - match : '\b(IMAGE_ATTACHMENT|DEPTH_STENCIL_ATTACHMENT|LOCATION|DEVICE_FEATURE)\b' scope: keyword.control.amber + - match : '\b(COPY|TOLERANCE|REPEAT)\b' + scope: keyword.control.amber - match: '\b(vertex|fragment|compute|geometry|tessellation_evaluation|tessellation_control)\b' scope: constant.character.escape.amber |