aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/amber_script.md18
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/amberscript/parser.cc102
-rw-r--r--src/amberscript/parser.h4
-rw-r--r--src/amberscript/parser_repeat_test.cc163
-rw-r--r--src/command.cc9
-rw-r--r--src/command.h35
-rw-r--r--src/executor.cc121
-rw-r--r--src/executor.h1
-rw-r--r--src/script.h5
-rw-r--r--src/vkscript/command_parser.cc8
-rw-r--r--src/vulkan/engine_vulkan.cc28
-rw-r--r--src/vulkan/pipeline.cc16
-rw-r--r--src/vulkan/pipeline.h6
-rw-r--r--tests/cases/repeat.amber36
-rw-r--r--tools/amber-syntax.vim3
-rw-r--r--tools/amber.sublime-syntax2
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