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
5 changes: 4 additions & 1 deletion docs/amber_script.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ The following commands are all specified within the `PIPELINE` command.
### Pipeline Buffers

#### Buffer Types
* `push_constant`
* `uniform`
* `storage`

Expand All @@ -217,6 +216,10 @@ attachment content, depth/stencil content, uniform buffers, etc.
# pipelines.
BIND BUFFER {buffer_name} AS depth_stencil

# Attach |buffer_name| as the push_constant buffer. There can be only one
# push constant buffer attached to a pipeline.
BIND BUFFER <buffer_name> AS push_constant

# Bind the buffer of the given |buffer_type| at the given descriptor set
# and binding. The buffer will use a start index of 0.
BIND BUFFER {buffer_name} AS {buffer_type} DESCRIPTOR_SET _id_ \
Expand Down
26 changes: 18 additions & 8 deletions src/amberscript/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -542,9 +542,7 @@ Result Parser::ParsePipelineFramebufferSize(Pipeline* pipeline) {

Result Parser::ToBufferType(const std::string& name, BufferType* type) {
assert(type);
if (name == "push_constant")
*type = BufferType::kPushConstant;
else if (name == "uniform")
if (name == "uniform")
*type = BufferType::kUniform;
else if (name == "storage")
*type = BufferType::kStorage;
Expand Down Expand Up @@ -596,6 +594,11 @@ Result Parser::ParsePipelineBind(Pipeline* pipeline) {
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);
Expand Down Expand Up @@ -1130,15 +1133,22 @@ Result Parser::ParseExpect() {
token->AsString());
}

if (buffer->GetBufferType() != buffer_2->GetBufferType())
if (!buffer->GetFormat()->Equal(buffer_2->GetFormat())) {
return Result(
"EXPECT EQ_BUFFER command cannot compare buffers of different type");
if (buffer->ElementCount() != buffer_2->ElementCount())
"EXPECT EQ_BUFFER command cannot compare buffers of differing "
"format");
}
if (buffer->ElementCount() != buffer_2->ElementCount()) {
return Result(
"EXPECT EQ_BUFFER command cannot compare buffers of different size");
if (buffer->GetWidth() != buffer_2->GetWidth())
"EXPECT EQ_BUFFER command cannot compare buffers of different "
"size: " +
std::to_string(buffer->ElementCount()) + " vs " +
std::to_string(buffer_2->ElementCount()));
}
if (buffer->GetWidth() != buffer_2->GetWidth()) {
return Result(
"EXPECT EQ_BUFFER command cannot compare buffers of different width");
}
if (buffer->GetHeight() != buffer_2->GetHeight()) {
return Result(
"EXPECT EQ_BUFFER command cannot compare buffers of different "
Expand Down
55 changes: 53 additions & 2 deletions src/amberscript/parser_bind_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1092,11 +1092,62 @@ PIPELINE graphics my_pipeline
INSTANTIATE_TEST_CASE_P(
AmberScriptParserBufferTypeTest,
AmberScriptParserBufferTypeTest,
testing::Values(BufferTypeData{"push_constant", BufferType::kPushConstant},
BufferTypeData{"uniform", BufferType::kUniform},
testing::Values(BufferTypeData{"uniform", BufferType::kUniform},
BufferTypeData{
"storage",
BufferType::kStorage}), ); // NOLINT(whitespace/parens)

TEST_F(AmberScriptParserTest, BindPushConstants) {
std::string in = R"(
SHADER vertex my_shader PASSTHROUGH
SHADER fragment my_fragment GLSL
# GLSL Shader
END
BUFFER my_buf DATA_TYPE float SIZE 20 FILL 5

PIPELINE graphics my_pipeline
ATTACH my_shader
ATTACH my_fragment

BIND BUFFER my_buf AS push_constant
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& buf = pipeline->GetPushConstantBuffer();
ASSERT_TRUE(buf.buffer != nullptr);
EXPECT_EQ(20, buf.buffer->ElementCount());
EXPECT_EQ(20, buf.buffer->ValueCount());
EXPECT_EQ(20 * sizeof(float), buf.buffer->GetSizeInBytes());
}

TEST_F(AmberScriptParserTest, BindPushConstantsExtraParams) {
std::string in = R"(
SHADER vertex my_shader PASSTHROUGH
SHADER fragment my_fragment GLSL
# GLSL Shader
END
BUFFER my_buf DATA_TYPE float SIZE 20 FILL 5

PIPELINE graphics my_pipeline
ATTACH my_shader
ATTACH my_fragment

BIND BUFFER my_buf AS push_constant EXTRA
END)";

Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("12: extra parameters after BIND command", r.Error());
}

} // namespace amberscript
} // namespace amber
5 changes: 3 additions & 2 deletions src/amberscript/parser_expect_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,8 @@ EXPECT buf_1 EQ_BUFFER buf_2
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ(
"5: EXPECT EQ_BUFFER command cannot compare buffers of different size",
"5: EXPECT EQ_BUFFER command cannot compare buffers of different size: "
"10 vs 99",
r.Error());
}

Expand All @@ -811,7 +812,7 @@ EXPECT buf_1 EQ_BUFFER buf_2
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ(
"5: EXPECT EQ_BUFFER command cannot compare buffers of different size",
"5: EXPECT EQ_BUFFER command cannot compare buffers of differing format",
r.Error());
}

Expand Down
15 changes: 13 additions & 2 deletions src/buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "src/buffer.h"

#include <cassert>
#include <cstring>

namespace amber {
namespace {
Expand Down Expand Up @@ -72,8 +73,8 @@ Result Buffer::CopyTo(Buffer* buffer) const {
}

Result Buffer::IsEqual(Buffer* buffer) const {
if (buffer->buffer_type_ != buffer_type_)
return Result{"Buffers have a different type"};
if (!buffer->format_->Equal(format_.get()))
return Result{"Buffers have a different format"};
if (buffer->element_count_ != element_count_)
return Result{"Buffers have a different size"};
if (buffer->width_ != width_)
Expand Down Expand Up @@ -215,4 +216,14 @@ void Buffer::ResizeTo(uint32_t element_count) {
bytes_.resize(element_count * format_->SizeInBytes());
}

Result Buffer::SetDataFromBuffer(const Buffer* src, uint32_t offset) {
if (bytes_.size() < offset + src->bytes_.size())
bytes_.resize(offset + src->bytes_.size());

std::memcpy(bytes_.data() + offset, src->bytes_.data(), src->bytes_.size());
element_count_ =
static_cast<uint32_t>(bytes_.size()) / format_->SizeInBytes();
return {};
}

} // namespace amber
5 changes: 4 additions & 1 deletion src/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class Buffer {
format_ = std::move(format);
}
/// Returns the Format describing the buffer data.
Format* GetFormat() { return format_.get(); }
Format* GetFormat() const { return format_.get(); }

/// Sets the buffer |name|.
void SetName(const std::string& name) { name_ = name; }
Expand Down Expand Up @@ -155,6 +155,9 @@ class Buffer {
/// |size_in_bytes| of data.
Result SetDataWithOffset(const std::vector<Value>& data, uint32_t offset);

/// Writes |src| data into buffer at |offset|.
Result SetDataFromBuffer(const Buffer* src, uint32_t offset);

/// Returns a pointer to the internal storage of the buffer.
std::vector<uint8_t>* ValuePtr() { return &bytes_; }
/// Returns a pointer to the internal storage of the buffer.
Expand Down
10 changes: 10 additions & 0 deletions src/pipeline.cc
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,16 @@ Result Pipeline::AddVertexBuffer(Buffer* buf, uint32_t location) {
return {};
}

Result Pipeline::SetPushConstantBuffer(Buffer* buf) {
if (push_constant_buffer_.buffer != nullptr)
return Result("can only bind one push constant buffer in a PIPELINE");
if (buf->GetBufferType() != BufferType::kPushConstant)
return Result("expected a push constant buffer");

push_constant_buffer_.buffer = buf;
return {};
}

std::unique_ptr<Buffer> Pipeline::GenerateDefaultColorAttachmentBuffer() const {
FormatParser fp;

Expand Down
6 changes: 6 additions & 0 deletions src/pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ class Pipeline {
/// |descriptor_set| and |binding|.
Buffer* GetBufferForBinding(uint32_t descriptor_set, uint32_t binding) const;

Result SetPushConstantBuffer(Buffer* buf);
const BufferInfo& GetPushConstantBuffer() const {
return push_constant_buffer_;
}

/// Validates that the pipeline has been created correctly.
Result Validate() const;

Expand All @@ -184,6 +189,7 @@ class Pipeline {
std::vector<BufferInfo> vertex_buffers_;
std::vector<BufferInfo> buffers_;
BufferInfo depth_buffer_;
BufferInfo push_constant_buffer_;
Buffer* index_buffer_ = nullptr;

uint32_t fb_width_ = 250;
Expand Down
7 changes: 7 additions & 0 deletions src/vulkan/engine_vulkan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,13 @@ Result EngineVulkan::CreatePipeline(amber::Pipeline* pipeline) {
info.vk_pipeline->AsGraphics()->SetIndexBuffer(buf);
}

if (pipeline->GetPushConstantBuffer().buffer != nullptr) {
r = info.vk_pipeline->AddPushConstantBuffer(
pipeline->GetPushConstantBuffer().buffer);
if (!r.IsSuccess())
return r;
}

for (const auto& buf_info : pipeline->GetBuffers()) {
auto type = BufferCommand::BufferType::kSSBO;
if (buf_info.buffer->GetBufferType() == BufferType::kUniform) {
Expand Down
6 changes: 5 additions & 1 deletion src/vulkan/pipeline.cc
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ Result Pipeline::CreateVkPipelineLayout(VkPipelineLayout* pipeline_layout) {

VkPushConstantRange push_const_range =
push_constant_->GetVkPushConstantRange();
if (push_const_range.size) {
if (push_const_range.size > 0) {
pipeline_layout_info.pushConstantRangeCount = 1U;
pipeline_layout_info.pPushConstantRanges = &push_const_range;
}
Expand Down Expand Up @@ -241,6 +241,10 @@ Result Pipeline::AddPushConstant(const BufferCommand* command) {
return push_constant_->AddBufferData(command);
}

Result Pipeline::AddPushConstantBuffer(const Buffer* buf) {
return push_constant_->AddBuffer(buf);
}

Result Pipeline::AddDescriptor(const BufferCommand* cmd) {
if (cmd == nullptr)
return Result("Pipeline::AddDescriptor BufferCommand is nullptr");
Expand Down
3 changes: 3 additions & 0 deletions src/vulkan/pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ class Pipeline {

Result AddDescriptor(const BufferCommand*);

/// Add buffer data to the push constants.
Result AddPushConstantBuffer(const Buffer* buf);

/// Reads back the contents of resources of all descriptors to a
/// buffer data object and put it into buffer data queue in host.
Result ReadbackDescriptorsToHostDataQueue();
Expand Down
19 changes: 17 additions & 2 deletions src/vulkan/push_constant.cc
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,20 @@ Result PushConstant::RecordPushConstantVkCommand(
return {};
}

Result PushConstant::AddBuffer(const Buffer* buffer) {
push_constant_data_.emplace_back();
push_constant_data_.back().offset = 0;
push_constant_data_.back().buffer = buffer;
push_constant_data_.back().format = buffer->GetFormat();
push_constant_data_.back().size_in_bytes = buffer->GetSizeInBytes();
return {};
}

Result PushConstant::AddBufferData(const BufferCommand* command) {
if (!command->IsPushConstant())
if (!command->IsPushConstant()) {
return Result(
"PushConstant::AddBufferData BufferCommand type is not push constant");
}

auto* fmt = command->GetBuffer()->GetFormat();
push_constant_data_.emplace_back();
Expand Down Expand Up @@ -134,7 +144,12 @@ Result PushConstant::UpdateMemoryWithInput(const BufferInput& input) {
return Result("Vulkan: push constants must all have the same format");

buffer_->SetFormat(MakeUnique<Format>(*input.format));
buffer_->SetDataWithOffset(input.values, input.offset);

if (input.buffer)
buffer_->SetDataFromBuffer(input.buffer, input.offset);
else
buffer_->SetDataWithOffset(input.values, input.offset);

return {};
}

Expand Down
20 changes: 14 additions & 6 deletions src/vulkan/push_constant.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,25 @@ class PushConstant {
Result RecordPushConstantVkCommand(CommandBuffer* command,
VkPipelineLayout pipeline_layout);

/// Add a set of values from the given |buffer| to the push constants
/// to be used on the next pipeline execution.
Result AddBuffer(const Buffer* buffer);

/// Adds data into the push constant buffer.
Result AddBufferData(const BufferCommand* command);

private:
// Contain information of filling memory
// [|offset|, |offset| + |size_in_bytes|) with |values| whose data
// type is |type|. This information is given by script.
// Contain information of filling memory.
// If the |buffer| is provided the buffer memory will be copied into the
// result buffer at |offset|. If |buffer| is not provided then
// |size_in_bytes|, |format| and |values| must be provided and will be copied
// into the result buffer at |offset|.
struct BufferInput {
uint32_t offset;
uint32_t size_in_bytes;
Format* format;
uint32_t offset = 0;
const Buffer* buffer = nullptr;

uint32_t size_in_bytes = 0;
Format* format = nullptr;
std::vector<Value> values;
};

Expand Down
Loading