Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/amber_script.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,20 @@ attachment content, depth/stencil content, uniform buffers, etc.
INDEX_DATA {buffer_name}
```

##### OpenCL Plain-Old-Data Arguments
OpenCL kernels can have plain-old-data (pod or pod_ubo in the desriptor map)
arguments set their data via this command. Amber will generate the appropriate
buffers for the pipeline populated with the specified data.

```groovy
# Set argument |name| to |data_type| with value |val|.
SET KERNEL ARG_NAME _name_ AS {data_type} _val_

# Set argument |number| to |data_type| with value |val|.
# Arguments use 0-based numbering.
SET KERNEL ARG_NUMBER _number_ AS {data_type} _val_
```

##### Topologies
* `point_list`
* `line_list`
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ if (${AMBER_ENABLE_TESTS})
amberscript/parser_extension_test.cc
amberscript/parser_framebuffer_test.cc
amberscript/parser_pipeline_test.cc
amberscript/parser_pipeline_set_test.cc
amberscript/parser_repeat_test.cc
amberscript/parser_run_test.cc
amberscript/parser_set_test.cc
Expand Down
65 changes: 65 additions & 0 deletions src/amberscript/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,8 @@ Result Parser::ParsePipelineBody(const std::string& cmd_name,
r = ParsePipelineVertexData(pipeline.get());
} else if (tok == "INDEX_DATA") {
r = ParsePipelineIndexData(pipeline.get());
} else if (tok == "SET") {
r = ParsePipelineSet(pipeline.get());
} else {
r = Result("unknown token in pipeline block: " + tok);
}
Expand Down Expand Up @@ -778,6 +780,69 @@ Result Parser::ParsePipelineIndexData(Pipeline* pipeline) {
return ValidateEndOfStatement("INDEX_DATA command");
}

Result Parser::ParsePipelineSet(Pipeline* pipeline) {
if (pipeline->GetShaders().empty() ||
pipeline->GetShaders()[0].GetShader()->GetFormat() !=
kShaderFormatOpenCLC) {
return Result("SET can only be used with OPENCL-C shaders");
}

auto token = tokenizer_->NextToken();
if (!token->IsString() || token->AsString() != "KERNEL")
return Result("missing KERNEL in SET command");

token = tokenizer_->NextToken();
if (!token->IsString())
return Result("expected ARG_NAME or ARG_NUMBER");

std::string arg_name = "";
uint32_t arg_no = std::numeric_limits<uint32_t>::max();
if (token->AsString() == "ARG_NAME") {
token = tokenizer_->NextToken();
if (!token->IsString())
return Result("expected argument identifier");
arg_name = token->AsString();
} else if (token->AsString() == "ARG_NUMBER") {
token = tokenizer_->NextToken();
if (!token->IsInteger())
return Result("expected argument number");
arg_no = token->AsUint32();
} else {
return Result("expected ARG_NAME or ARG_NUMBER");
}

token = tokenizer_->NextToken();
if (!token->IsString() || token->AsString() != "AS")
return Result("missing AS in SET command");

token = tokenizer_->NextToken();
if (!token->IsString())
return Result("expected data type");

DatumType arg_type;
auto r = ToDatumType(token->AsString(), &arg_type);
if (!r.IsSuccess())
return r;

token = tokenizer_->NextToken();
if (!token->IsInteger() && !token->IsDouble())
return Result("expected data value");

Value value;
if (arg_type.IsFloat() || arg_type.IsDouble())
value.SetDoubleValue(token->AsDouble());
else
value.SetIntValue(token->AsUint64());

Pipeline::ArgSetInfo info;
info.name = arg_name;
info.ordinal = arg_no;
info.type = arg_type;
info.value = value;
pipeline->SetArg(std::move(info));
return ValidateEndOfStatement("SET command");
}

Result Parser::ParseBuffer() {
auto token = tokenizer_->NextToken();
if (!token->IsString())
Expand Down
1 change: 1 addition & 0 deletions src/amberscript/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class Parser : public amber::Parser {
Result ParsePipelineBind(Pipeline*);
Result ParsePipelineVertexData(Pipeline*);
Result ParsePipelineIndexData(Pipeline*);
Result ParsePipelineSet(Pipeline*);
Result ParseRun();
Result ParseClear();
Result ParseClearColor();
Expand Down
245 changes: 245 additions & 0 deletions src/amberscript/parser_pipeline_set_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
// 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, OpenCLSetMissingKernel) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we test that SET is called on an OPENCL-C shader type?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way the buffers are generated, the information in the SET is ignored if the shader is not an OPENCL-C shader. Would you prefer an error to that behaviour?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concern is that you either set the shader type wrong, or are trying to use set for something it isn't designed for at this point. So, even though it will do nothing, I think it would be useful to generate an error to say something along the lines of "SET must be used with OPENCL shaders`

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll add an error.

std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
PIPELINE compute my_pipeline
ATTACH my_shader
SET ARG_NAME a AS uint32 0
END
)";

Parser parser;
auto r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: missing KERNEL in SET command", r.Error());
}

TEST_F(AmberScriptParserTest, OpenCLSetMissingArgName) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
PIPELINE compute my_pipeline
ATTACH my_shader
SET KERNEL a AS uint32 0
END
)";

Parser parser;
auto r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: expected ARG_NAME or ARG_NUMBER", r.Error());
}

TEST_F(AmberScriptParserTest, OpenCLSetMissingArgIdentifier) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
PIPELINE compute my_pipeline
ATTACH my_shader
SET KERNEL ARG_NAME AS uint32 0
END
)";

Parser parser;
auto r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: missing AS in SET command", r.Error());
}

TEST_F(AmberScriptParserTest, OpenCLSetMissingArgIdentifierNumber) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
PIPELINE compute my_pipeline
ATTACH my_shader
SET KERNEL ARG_NUMBER AS uint32 0
END
)";

Parser parser;
auto r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: expected argument number", r.Error());
}

TEST_F(AmberScriptParserTest, OpenCLSetMissingAs) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
PIPELINE compute my_pipeline
ATTACH my_shader
SET KERNEL ARG_NAME a uint32 0
END
)";

Parser parser;
auto r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: missing AS in SET command", r.Error());
}

TEST_F(AmberScriptParserTest, OpenCLSetMissingDataType) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
PIPELINE compute my_pipeline
ATTACH my_shader
SET KERNEL ARG_NAME a AS 0
END
)";

Parser parser;
auto r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: expected data type", r.Error());
}

TEST_F(AmberScriptParserTest, OpenCLSetMissingDataValue) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
PIPELINE compute my_pipeline
ATTACH my_shader
SET KERNEL ARG_NAME a AS uint32
END
)";

Parser parser;
auto r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("8: expected data value", r.Error());
}

TEST_F(AmberScriptParserTest, OpenCLSetExtraTokens) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
PIPELINE compute my_pipeline
ATTACH my_shader
SET KERNEL ARG_NAME a AS uint32 0 BLAH
END
)";

Parser parser;
auto r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: extra parameters after SET command", r.Error());
}

TEST_F(AmberScriptParserTest, OpenCLSetArgNameNotString) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
PIPELINE compute my_pipeline
ATTACH my_shader
SET KERNEL ARG_NAME 0 AS uint32 0
END
)";

Parser parser;
auto r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: expected argument identifier", r.Error());
}

TEST_F(AmberScriptParserTest, OpenCLSetArgNumberNotInteger) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
PIPELINE compute my_pipeline
ATTACH my_shader
SET KERNEL ARG_NUMBER 1.0 AS uint32 0
END
)";

Parser parser;
auto r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: expected argument number", r.Error());
}

TEST_F(AmberScriptParserTest, OpenCLSetDataTypeNotString) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
PIPELINE compute my_pipeline
ATTACH my_shader
SET KERNEL ARG_NUMBER 0 AS 0 0
END
)";

Parser parser;
auto r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: expected data type", r.Error());
}

TEST_F(AmberScriptParserTest, OpenCLSetDataValueString) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
PIPELINE compute my_pipeline
ATTACH my_shader
SET KERNEL ARG_NUMBER 0 AS uint32 data
END
)";

Parser parser;
auto r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: expected data value", r.Error());
}

TEST_F(AmberScriptParserTest, OpenCLSetWrongShaderFormat) {
std::string in = R"(
SHADER compute my_shader SPIRV-ASM
#shader
END
PIPELINE compute my_pipeline
ATTACH my_shader
SET KERNEL ARG_NAME arg_a AS uint32 0
END
)";

Parser parser;
auto r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("7: SET can only be used with OPENCL-C shaders", r.Error());
}

} // namespace amberscript
} // namespace amber
2 changes: 0 additions & 2 deletions src/clspv_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ Result Compile(Pipeline::ShaderInfo* shader_info,

if (entry.kernel_arg_data.arg_kind == clspv::ArgKind::Pod ||
entry.kernel_arg_data.arg_kind == clspv::ArgKind::PodUBO) {
if (entry.kernel_arg_data.pod_offset != 0)
return Result("Clustered PoD arguments are not currently supported");
descriptor_entry.pod_offset = entry.kernel_arg_data.pod_offset;
descriptor_entry.pod_arg_size = entry.kernel_arg_data.pod_arg_size;
}
Expand Down
7 changes: 7 additions & 0 deletions src/executor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,17 @@ Result Executor::Execute(Engine* engine,
if (!r.IsSuccess())
return r;

// OpenCL specific pipeline updates.
for (auto& pipeline : script->GetPipelines()) {
r = pipeline->UpdateOpenCLBufferBindings();
if (!r.IsSuccess())
return r;
r = pipeline->GenerateOpenCLPodBuffers();
if (!r.IsSuccess())
return r;
}

for (auto& pipeline : script->GetPipelines()) {
r = engine->CreatePipeline(pipeline.get());
if (!r.IsSuccess())
return r;
Expand Down
Loading