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
11 changes: 11 additions & 0 deletions docs/amber_script.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,17 @@ attachment content, depth/stencil content, uniform buffers, etc.

# Bind the sampler at the given descriptor set and binding.
BIND SAMPLER {sampler_name} DESCRIPTOR_SET _id_ BINDING _id_

# Bind OpenCL argument buffer by name. Specifying the buffer type is optional.
# Amber will set the type as appropriate for the argument buffer. All uses
# of the buffer must have a consistent |buffer_type| across all pipelines.
BIND BUFFER {buffer_name} [AS {buffer_type}] KERNEL ARG_NAME _name_

# Bind OpenCL argument buffer by argument ordinal. Arguments use 0-based
# numbering. Specifying the buffer type is optional. Amber will set the
# type as appropriate for the argument buffer. All uses of the buffer
# must have a consistent |buffer_type| across all pipelines.
BIND BUFFER {buffer_name} [AS {buffer_type}] KERNEL ARG_NUMBER _number_
```

```groovy
Expand Down
126 changes: 77 additions & 49 deletions src/amberscript/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -644,65 +644,93 @@ Result Parser::ParsePipelineBind(Pipeline* pipeline) {
return Result("unknown buffer: " + token->AsString());

token = tokenizer_->NextToken();
if (!token->IsString() || token->AsString() != "AS")
return Result("BUFFER command missing AS keyword");
if (token->IsString() && token->AsString() == "AS") {
token = tokenizer_->NextToken();
if (!token->IsString())
return Result("invalid token for BUFFER type");

token = tokenizer_->NextToken();
if (!token->IsString())
return Result("invalid token for BUFFER type");
if (token->AsString() == "color") {
token = tokenizer_->NextToken();
if (!token->IsString() || token->AsString() != "LOCATION")
return Result("BIND missing LOCATION");

if (token->AsString() == "color") {
token = tokenizer_->NextToken();
if (!token->IsString() || token->AsString() != "LOCATION")
return Result("BIND missing LOCATION");
token = tokenizer_->NextToken();
if (!token->IsInteger())
return Result("invalid value for BIND LOCATION");

token = tokenizer_->NextToken();
if (!token->IsInteger())
return Result("invalid value for BIND LOCATION");
buffer->SetBufferType(BufferType::kColor);

buffer->SetBufferType(BufferType::kColor);
Result r = pipeline->AddColorAttachment(buffer, token->AsUint32());
if (!r.IsSuccess())
return r;
} else if (token->AsString() == "depth_stencil") {
buffer->SetBufferType(BufferType::kDepth);
Result r = pipeline->SetDepthBuffer(buffer);
if (!r.IsSuccess())
return r;
} else if (token->AsString() == "push_constant") {
buffer->SetBufferType(BufferType::kPushConstant);
Result r = pipeline->SetPushConstantBuffer(buffer);
if (!r.IsSuccess())
return r;
} else {
BufferType type = BufferType::kColor;
Result r = ToBufferType(token->AsString(), &type);
if (!r.IsSuccess())
return r;

Result r = pipeline->AddColorAttachment(buffer, token->AsUint32());
if (!r.IsSuccess())
return r;
} else if (token->AsString() == "depth_stencil") {
buffer->SetBufferType(BufferType::kDepth);
Result r = pipeline->SetDepthBuffer(buffer);
if (!r.IsSuccess())
return r;
} else if (token->AsString() == "push_constant") {
buffer->SetBufferType(BufferType::kPushConstant);
Result r = pipeline->SetPushConstantBuffer(buffer);
if (!r.IsSuccess())
return r;
} else {
BufferType type = BufferType::kColor;
Result r = ToBufferType(token->AsString(), &type);
if (!r.IsSuccess())
return r;
if (buffer->GetBufferType() == BufferType::kUnknown)
buffer->SetBufferType(type);
else if (buffer->GetBufferType() != type)
return Result("buffer type does not match intended usage");
}
}

if (buffer->GetBufferType() == BufferType::kUnknown)
buffer->SetBufferType(type);
else if (buffer->GetBufferType() != type)
return Result("buffer type does not match intended usage");
if (buffer->GetBufferType() == BufferType::kUnknown ||
buffer->GetBufferType() == BufferType::kStorage ||
buffer->GetBufferType() == BufferType::kUniform) {
// If AS was parsed above consume the next token.
if (buffer->GetBufferType() != BufferType::kUnknown)
token = tokenizer_->NextToken();
// DESCRIPTOR_SET requires a buffer type to have been specified.
if (buffer->GetBufferType() != BufferType::kUnknown && token->IsString() &&
token->AsString() == "DESCRIPTOR_SET") {
token = tokenizer_->NextToken();
if (!token->IsInteger())
return Result("invalid value for DESCRIPTOR_SET in BIND command");
uint32_t descriptor_set = token->AsUint32();

token = tokenizer_->NextToken();
if (!token->IsString() || token->AsString() != "DESCRIPTOR_SET")
return Result("missing DESCRIPTOR_SET for BIND command");
token = tokenizer_->NextToken();
if (!token->IsString() || token->AsString() != "BINDING")
return Result("missing BINDING for BIND command");

token = tokenizer_->NextToken();
if (!token->IsInteger())
return Result("invalid value for DESCRIPTOR_SET in BIND command");
uint32_t descriptor_set = token->AsUint32();
token = tokenizer_->NextToken();
if (!token->IsInteger())
return Result("invalid value for BINDING in BIND command");
pipeline->AddBuffer(buffer, descriptor_set, token->AsUint32());
} else if (token->IsString() && token->AsString() == "KERNEL") {
token = tokenizer_->NextToken();
if (!token->IsString())
return Result("missing kernel arg identifier");

token = tokenizer_->NextToken();
if (!token->IsString() || token->AsString() != "BINDING")
return Result("missing BINDING for BIND command");
if (token->AsString() == "ARG_NAME") {
token = tokenizer_->NextToken();
if (!token->IsString())
return Result("expected argument identifier");

token = tokenizer_->NextToken();
if (!token->IsInteger())
return Result("invalid value for BINDING in BIND command");
pipeline->AddBuffer(buffer, descriptor_set, token->AsUint32());
pipeline->AddBuffer(buffer, token->AsString());
} else if (token->AsString() == "ARG_NUMBER") {
token = tokenizer_->NextToken();
if (!token->IsInteger())
return Result("expected argument number");

pipeline->AddBuffer(buffer, token->AsUint32());
} else {
return Result("missing ARG_NAME or ARG_NUMBER keyword");
}
} else {
return Result("missing DESCRIPTOR_SET or KERNEL for BIND command");
}
}

return ValidateEndOfStatement("BIND command");
Expand Down
178 changes: 177 additions & 1 deletion src/amberscript/parser_bind_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,7 @@ END)";
Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("12: missing DESCRIPTOR_SET for BIND command", r.Error());
EXPECT_EQ("12: missing DESCRIPTOR_SET or KERNEL for BIND command", r.Error());
}

TEST_F(AmberScriptParserTest, BindingBufferExtraParams) {
Expand Down Expand Up @@ -1149,5 +1149,181 @@ END)";
EXPECT_EQ("12: extra parameters after BIND command", r.Error());
}

TEST_F(AmberScriptParserTest, BindBufferOpenCLArgName) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
BUFFER my_buf DATA_TYPE uint32 DATA 1 END

PIPELINE compute my_pipeline
ATTACH my_shader
BIND BUFFER my_buf AS storage KERNEL ARG_NAME arg
END)";

Parser parser;
Result r = parser.Parse(in);
ASSERT_TRUE(r.IsSuccess());
}

TEST_F(AmberScriptParserTest, BindBufferOpenCLArgNumber) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
BUFFER my_buf DATA_TYPE uint32 DATA 1 END

PIPELINE compute my_pipeline
ATTACH my_shader
BIND BUFFER my_buf AS storage KERNEL ARG_NUMBER 0
END)";

Parser parser;
Result r = parser.Parse(in);
ASSERT_TRUE(r.IsSuccess());
}

TEST_F(AmberScriptParserTest, BindBufferOpenCLArgNameTypeless) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
BUFFER my_buf DATA_TYPE uint32 DATA 1 END

PIPELINE compute my_pipeline
ATTACH my_shader
BIND BUFFER my_buf KERNEL ARG_NAME arg
END)";

Parser parser;
Result r = parser.Parse(in);
ASSERT_TRUE(r.IsSuccess());
}

TEST_F(AmberScriptParserTest, BindBufferOpenCLArgNumberTypeless) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
BUFFER my_buf DATA_TYPE uint32 DATA 1 END

PIPELINE compute my_pipeline
ATTACH my_shader
BIND BUFFER my_buf KERNEL ARG_NUMBER 0
END)";

Parser parser;
Result r = parser.Parse(in);
ASSERT_TRUE(r.IsSuccess());
}

TEST_F(AmberScriptParserTest, BindBufferOpenCLMissingKernel) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
BUFFER my_buf DATA_TYPE uint32 DATA 1 END

PIPELINE compute my_pipeline
ATTACH my_shader
BIND BUFFER my_buf AS storage ARG_NAME arg
END)";

Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("9: missing DESCRIPTOR_SET or KERNEL for BIND command", r.Error());
}

TEST_F(AmberScriptParserTest, BindBufferOpenCLMissingArg) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
BUFFER my_buf DATA_TYPE uint32 DATA 1 END

PIPELINE compute my_pipeline
ATTACH my_shader
BIND BUFFER my_buf AS storage KERNEL arg
END)";

Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("9: missing ARG_NAME or ARG_NUMBER keyword", r.Error());
}

TEST_F(AmberScriptParserTest, BindBufferOpenCLMissingArgName) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
BUFFER my_buf DATA_TYPE uint32 DATA 1 END

PIPELINE compute my_pipeline
ATTACH my_shader
BIND BUFFER my_buf KERNEL ARG_NAME
END)";

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

TEST_F(AmberScriptParserTest, BindBufferOpenCLMissingArgNumber) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
BUFFER my_buf DATA_TYPE uint32 DATA 1 END

PIPELINE compute my_pipeline
ATTACH my_shader
BIND BUFFER my_buf AS storage KERNEL ARG_NUMBER
END)";

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

TEST_F(AmberScriptParserTest, BindBufferOpenCLArgNameNotString) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
BUFFER my_buf DATA_TYPE uint32 DATA 1 END

PIPELINE compute my_pipeline
ATTACH my_shader
BIND BUFFER my_buf AS storage KERNEL ARG_NAME 0
END)";

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

TEST_F(AmberScriptParserTest, BindBufferOpenCLArgNumberNotInteger) {
std::string in = R"(
SHADER compute my_shader OPENCL-C
#shader
END
BUFFER my_buf DATA_TYPE uint32 DATA 1 END

PIPELINE compute my_pipeline
ATTACH my_shader
BIND BUFFER my_buf KERNEL ARG_NUMBER in
END)";

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

} // namespace amberscript
} // namespace amber
Loading