diff options
-rw-r--r-- | docs/amber_script.md | 7 | ||||
-rw-r--r-- | include/amber/amber.h | 15 | ||||
-rw-r--r-- | samples/amber.cc | 40 | ||||
-rw-r--r-- | src/amberscript/parser.cc | 42 | ||||
-rw-r--r-- | src/amberscript/parser_buffer_test.cc | 69 | ||||
-rw-r--r-- | src/buffer.h | 12 | ||||
-rw-r--r-- | src/executor.cc | 14 | ||||
-rw-r--r-- | tests/cases/buffer_load_binary.amber | 55 | ||||
-rw-r--r-- | tests/cases/draw_png_texture.amber | 2 | ||||
-rw-r--r-- | tests/cases/vec4data.bin | bin | 0 -> 48 bytes |
10 files changed, 235 insertions, 21 deletions
diff --git a/docs/amber_script.md b/docs/amber_script.md index f1540f9..c935d5b 100644 --- a/docs/amber_script.md +++ b/docs/amber_script.md @@ -193,6 +193,11 @@ BUFFER {name} DATA_TYPE {type} {STD140 | STD430} SIZE _size_in_items_ \ BUFFER {name} DATA_TYPE {type} {STD140 | STD430} WIDTH {w} HEIGHT {h} \ {initializer} +# Defines a buffer which is filled with binary data from a file specified +# by `FILE`. +BUFFER {name} DATA_TYPE {type} {STD140 | STD430} SIZE _size_in_items_ \ + FILE BINARY {file_name} + # Creates a buffer which will store the given `FORMAT` of data. These # buffers are used as image and depth buffers in the `PIPELINE` commands. # The buffer will be sized based on the `RENDER_SIZE` of the `PIPELINE`. @@ -202,7 +207,7 @@ BUFFER {name} FORMAT {format_string} \ # Load buffer data from a PNG image with file name specified by `FILE`. # The file path is relative to the script file being run. Format specified # by `FORMAT` must match the image format. -BUFFER {name} FORMAT {format_string} FILE {file_name.png} +BUFFER {name} FORMAT {format_string} FILE PNG {file_name.png} ``` #### Images diff --git a/include/amber/amber.h b/include/amber/amber.h index b665de2..ddf5779 100644 --- a/include/amber/amber.h +++ b/include/amber/amber.h @@ -50,7 +50,7 @@ struct EngineConfig { virtual ~EngineConfig(); }; -/// Stores information for a biffer. +/// Stores information for a buffer. struct BufferInfo { BufferInfo(); BufferInfo(const BufferInfo&); @@ -70,6 +70,18 @@ struct BufferInfo { std::vector<Value> values; }; +/// Types of source file to load buffer data from. +enum class BufferDataFileType : int8_t { + /// Unknown file type + kUnknown = -1, + /// A text file + kText = 0, + /// A binary file + kBinary, + /// A PNG file + kPng +}; + /// Delegate class for various hook functions class Delegate { public: @@ -87,6 +99,7 @@ class Delegate { virtual bool LogExecuteCalls() const = 0; /// Loads buffer data from a file virtual amber::Result LoadBufferData(const std::string file_name, + BufferDataFileType file_type, amber::BufferInfo* buffer) const = 0; }; diff --git a/samples/amber.cc b/samples/amber.cc index 31e66f9..01ff159 100644 --- a/samples/amber.cc +++ b/samples/amber.cc @@ -254,7 +254,7 @@ bool ParseArgs(const std::vector<std::string>& args, Options* opts) { return true; } -std::string ReadFile(const std::string& input_file) { +std::vector<char> ReadFile(const std::string& input_file) { FILE* file = nullptr; #if defined(_MSC_VER) fopen_s(&file, input_file.c_str(), "rb"); @@ -287,7 +287,7 @@ std::string ReadFile(const std::string& input_file) { return {}; } - return std::string(data.begin(), data.end()); + return data; } class SampleDelegate : public amber::Delegate { @@ -327,19 +327,36 @@ class SampleDelegate : public amber::Delegate { void SetScriptPath(std::string path) { path_ = path; } amber::Result LoadBufferData(const std::string file_name, + amber::BufferDataFileType file_type, amber::BufferInfo* buffer) const override { + if (file_type == amber::BufferDataFileType::kPng) { #if AMBER_ENABLE_LODEPNG - // Try to load as png first. - amber::Result r = png::LoadPNG(path_ + file_name, &buffer->width, - &buffer->height, &buffer->values); - - if (r.IsSuccess()) - return r; + return png::LoadPNG(path_ + file_name, &buffer->width, &buffer->height, + &buffer->values); +#else + return amber::Result("PNG support is not enabled in compile options."); #endif // AMBER_ENABLE_LODEPNG + } else if (file_type == amber::BufferDataFileType::kBinary) { + auto data = ReadFile(path_ + file_name); + if (data.empty()) + return amber::Result("Failed to load buffer data " + file_name); + + for (auto d : data) { + amber::Value v; + v.SetIntValue(static_cast<uint64_t>(d)); + buffer->values.push_back(v); + } + + buffer->width = 1; + buffer->height = 1; - // TODO(asuonpaa): Try to load a binary format. + } else { + assert(file_type == amber::BufferDataFileType::kText); - return amber::Result("Failed to load buffer data " + file_name); + // TODO(asuonpaa): Read text file and pass it to parser. + } + + return {}; } private: @@ -432,7 +449,8 @@ int main(int argc, const char** argv) { }; std::vector<RecipeData> recipe_data; for (const auto& file : options.input_filenames) { - auto data = ReadFile(file); + auto char_data = ReadFile(file); + auto data = std::string(char_data.begin(), char_data.end()); if (data.empty()) { std::cerr << file << " is empty." << std::endl; failures.push_back(file); diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc index 10162b8..bc18271 100644 --- a/src/amberscript/parser.cc +++ b/src/amberscript/parser.cc @@ -1265,7 +1265,22 @@ Result Parser::ParseBuffer() { if (!token->IsIdentifier()) return Result("invalid value for FILE"); - buffer->SetDataFile(token->AsString()); + BufferDataFileType file_type = BufferDataFileType::kPng; + + if (token->AsString() == "TEXT") { + file_type = BufferDataFileType::kText; + token = tokenizer_->NextToken(); + } else if (token->AsString() == "BINARY") { + file_type = BufferDataFileType::kBinary; + token = tokenizer_->NextToken(); + } else if (token->AsString() == "PNG") { + token = tokenizer_->NextToken(); + } + + if (!token->IsIdentifier()) + return Result("missing file name for FILE"); + + buffer->SetDataFile(token->AsString(), file_type); } else { break; } @@ -1516,6 +1531,31 @@ Result Parser::ParseBufferInitializerSize(Buffer* buffer) { return ParseBufferInitializerFill(buffer, size_in_items); if (token->AsString() == "SERIES_FROM") return ParseBufferInitializerSeries(buffer, size_in_items); + if (token->AsString() == "FILE") { + token = tokenizer_->NextToken(); + + if (!token->IsIdentifier()) + return Result("invalid value for FILE"); + + BufferDataFileType file_type = BufferDataFileType::kPng; + + if (token->AsString() == "TEXT") { + file_type = BufferDataFileType::kText; + token = tokenizer_->NextToken(); + } else if (token->AsString() == "BINARY") { + file_type = BufferDataFileType::kBinary; + token = tokenizer_->NextToken(); + } else if (token->AsString() == "PNG") { + token = tokenizer_->NextToken(); + } + + if (!token->IsIdentifier()) + return Result("missing file name for FILE"); + + buffer->SetDataFile(token->AsString(), file_type); + + return {}; + } return Result("invalid BUFFER initializer provided"); } diff --git a/src/amberscript/parser_buffer_test.cc b/src/amberscript/parser_buffer_test.cc index d2f1eb1..023b9ba 100644 --- a/src/amberscript/parser_buffer_test.cc +++ b/src/amberscript/parser_buffer_test.cc @@ -1077,8 +1077,18 @@ TEST_F(AmberScriptParserTest, BufferMissingDataFile) { EXPECT_EQ("1: invalid value for FILE", r.Error()); } -TEST_F(AmberScriptParserTest, BufferDataFile) { - std::string in = "BUFFER my_buffer FORMAT R8G8B8A8_UNORM FILE foo.png"; +TEST_F(AmberScriptParserTest, BufferMissingDataFilePng) { + std::string in = "BUFFER my_buffer FORMAT R8G8B8A8_UNORM FILE PNG"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + + EXPECT_EQ("1: missing file name for FILE", r.Error()); +} + +TEST_F(AmberScriptParserTest, BufferDataFilePng) { + std::string in = "BUFFER my_buffer FORMAT R8G8B8A8_UNORM FILE PNG foo.png"; Parser parser; Result r = parser.Parse(in); @@ -1090,6 +1100,61 @@ TEST_F(AmberScriptParserTest, BufferDataFile) { ASSERT_TRUE(buffers[0] != nullptr); EXPECT_EQ("foo.png", buffers[0]->GetDataFile()); + EXPECT_EQ(BufferDataFileType::kPng, buffers[0]->GetDataFileType()); +} + +TEST_F(AmberScriptParserTest, BufferMissingDataFileBinary) { + std::string in = "BUFFER my_buffer DATA_TYPE float SIZE 10 FILE BINARY"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + + EXPECT_EQ("1: missing file name for FILE", r.Error()); +} + +TEST_F(AmberScriptParserTest, BufferDataFileBinary) { + std::string in = + "BUFFER my_buffer DATA_TYPE int32 SIZE 10 FILE BINARY data.bin"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& buffers = script->GetBuffers(); + ASSERT_EQ(1U, buffers.size()); + + ASSERT_TRUE(buffers[0] != nullptr); + EXPECT_EQ("data.bin", buffers[0]->GetDataFile()); + EXPECT_EQ(BufferDataFileType::kBinary, buffers[0]->GetDataFileType()); +} + +TEST_F(AmberScriptParserTest, BufferMissingDataFileText) { + std::string in = "BUFFER my_buffer DATA_TYPE float SIZE 10 FILE TEXT"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + + EXPECT_EQ("1: missing file name for FILE", r.Error()); +} + +TEST_F(AmberScriptParserTest, BufferDataFileText) { + std::string in = + "BUFFER my_buffer DATA_TYPE int32 SIZE 10 FILE TEXT data.txt"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& buffers = script->GetBuffers(); + ASSERT_EQ(1U, buffers.size()); + + ASSERT_TRUE(buffers[0] != nullptr); + EXPECT_EQ("data.txt", buffers[0]->GetDataFile()); + EXPECT_EQ(BufferDataFileType::kText, buffers[0]->GetDataFileType()); } } // namespace amberscript diff --git a/src/buffer.h b/src/buffer.h index 9d6f3d6..be44a1f 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -21,6 +21,7 @@ #include <utility> #include <vector> +#include "amber/amber.h" #include "amber/result.h" #include "amber/value.h" #include "src/format.h" @@ -194,14 +195,20 @@ class Buffer { void SetMipLevels(uint32_t mip_levels) { mip_levels_ = mip_levels; } /// Returns the number of mip levels. - uint32_t GetMipLevels() { return mip_levels_; } + uint32_t GetMipLevels() const { return mip_levels_; } /// Sets the file name for loading data into the buffer. - void SetDataFile(std::string data_file) { data_file_ = data_file; } + void SetDataFile(std::string data_file, BufferDataFileType type) { + data_file_ = data_file; + data_file_type_ = type; + } /// Returns the file name used to load buffer data from. std::string GetDataFile() { return data_file_; } + /// Returns the file type to load buffer data from. + BufferDataFileType GetDataFileType() const { return data_file_type_; } + /// 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. @@ -259,6 +266,7 @@ class Buffer { Sampler* sampler_ = nullptr; ImageDimension image_dim_ = ImageDimension::kUnknown; std::string data_file_; + BufferDataFileType data_file_type_ = BufferDataFileType::kUnknown; }; } // namespace amber diff --git a/src/executor.cc b/src/executor.cc index 30f6fb5..3470cbe 100644 --- a/src/executor.cc +++ b/src/executor.cc @@ -95,11 +95,21 @@ Result Executor::Execute(Engine* engine, continue; BufferInfo info; - Result r = options->delegate->LoadBufferData(buf->GetDataFile(), &info); + Result r = options->delegate->LoadBufferData(buf->GetDataFile(), + buf->GetDataFileType(), &info); if (!r.IsSuccess()) return r; - buf->SetData(info.values); + std::vector<uint8_t>* data = buf->ValuePtr(); + + data->clear(); + data->reserve(info.values.size()); + for (auto v : info.values) { + data->push_back(v.AsUint8()); + } + + buf->SetElementCount(static_cast<uint32_t>(data->size()) / + buf->GetFormat()->SizeInBytes()); buf->SetWidth(info.width); buf->SetHeight(info.height); } diff --git a/tests/cases/buffer_load_binary.amber b/tests/cases/buffer_load_binary.amber new file mode 100644 index 0000000..2eae472 --- /dev/null +++ b/tests/cases/buffer_load_binary.amber @@ -0,0 +1,55 @@ +#!amber +# +# Copyright 2020 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 compute_shader GLSL +#version 430 + +layout(set = 0, binding = 0) buffer block0 { + float in_data[12]; +}; + +layout(set = 0, binding = 1) buffer block1 { + float out_data[12]; +}; + +void main() { + for (int i = 0; i < 12; i++) + out_data[i] = in_data[i] * 2.0; +} +END + +BUFFER buf0 DATA_TYPE vec4<float> SIZE 3 FILE BINARY vec4data.bin +BUFFER buf1 DATA_TYPE vec4<float> SIZE 3 FILL 0.0 + +BUFFER ref0 DATA_TYPE vec4<float> DATA +1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 +END + +BUFFER ref1 DATA_TYPE vec4<float> DATA +2.0 4.0 6.0 8.0 10.0 12.0 14.0 16.0 18.0 20.0 22.0 24.0 +END + +PIPELINE compute pipeline + ATTACH compute_shader + + BIND BUFFER buf0 AS storage DESCRIPTOR_SET 0 BINDING 0 + BIND BUFFER buf1 AS storage DESCRIPTOR_SET 0 BINDING 1 +END + +RUN pipeline 1 1 1 + +EXPECT buf0 EQ_BUFFER ref0 +EXPECT buf1 EQ_BUFFER ref1 diff --git a/tests/cases/draw_png_texture.amber b/tests/cases/draw_png_texture.amber index c7b9885..b314624 100644 --- a/tests/cases/draw_png_texture.amber +++ b/tests/cases/draw_png_texture.amber @@ -34,7 +34,7 @@ void main() { } END -BUFFER texture FORMAT R8G8B8A8_UNORM FILE texture.png +BUFFER texture FORMAT R8G8B8A8_UNORM FILE PNG texture.png BUFFER framebuffer FORMAT B8G8R8A8_UNORM SAMPLER sampler BUFFER position DATA_TYPE vec2<float> DATA diff --git a/tests/cases/vec4data.bin b/tests/cases/vec4data.bin Binary files differnew file mode 100644 index 0000000..1c60b14 --- /dev/null +++ b/tests/cases/vec4data.bin |