aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorasuonpaa <34128694+asuonpaa@users.noreply.github.com>2020-03-24 14:43:27 +0200
committerGitHub <noreply@github.com>2020-03-24 08:43:27 -0400
commit38fcbe6700f725b80a68168f046ac86020254500 (patch)
tree09e6984d6b052d418bd4c44e4533e684eee67cbc
parentd4ab26cbc3d53f5dfcb38ede4ea4eadbb6da6be3 (diff)
downloadamber-38fcbe6700f725b80a68168f046ac86020254500.tar.gz
Added a support for loading a png file into a buffer (#823)
This CL adds the `FILE` parameter to `BUFFER` commands. This allows loading file data into the buffer. Currently only PNG data is supported.
-rw-r--r--docs/amber_script.md5
-rw-r--r--include/amber/amber.h3
-rw-r--r--samples/amber.cc22
-rw-r--r--samples/png.cc19
-rw-r--r--samples/png.h8
-rw-r--r--src/amberscript/parser.cc25
-rw-r--r--src/amberscript/parser_buffer_test.cc25
-rw-r--r--src/buffer.h7
-rw-r--r--src/executor.cc15
-rw-r--r--tests/cases/draw_png_texture.amber66
-rw-r--r--tests/cases/texture.pngbin0 -> 32776 bytes
-rwxr-xr-xtests/run_tests.py2
12 files changed, 190 insertions, 7 deletions
diff --git a/docs/amber_script.md b/docs/amber_script.md
index 1191d60..56430f7 100644
--- a/docs/amber_script.md
+++ b/docs/amber_script.md
@@ -156,6 +156,11 @@ BUFFER {name} DATA_TYPE {type} {STD140 | STD430} WIDTH {w} HEIGHT {h} \
# The buffer will be sized based on the `RENDER_SIZE` of the `PIPELINE`.
BUFFER {name} FORMAT {format_string} \
[ MIP_LEVELS _mip_levels_ (default 1) ]
+
+# 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}
```
#### Images
diff --git a/include/amber/amber.h b/include/amber/amber.h
index 1fffd38..b665de2 100644
--- a/include/amber/amber.h
+++ b/include/amber/amber.h
@@ -85,6 +85,9 @@ class Delegate {
virtual uint64_t GetTimestampNs() const = 0;
/// Tells whether to log each test as it's executed
virtual bool LogExecuteCalls() const = 0;
+ /// Loads buffer data from a file
+ virtual amber::Result LoadBufferData(const std::string file_name,
+ amber::BufferInfo* buffer) const = 0;
};
/// Stores configuration options for Amber.
diff --git a/samples/amber.cc b/samples/amber.cc
index 221da50..31e66f9 100644
--- a/samples/amber.cc
+++ b/samples/amber.cc
@@ -324,10 +324,29 @@ class SampleDelegate : public amber::Delegate {
return timestamp::SampleGetTimestampNs();
}
+ void SetScriptPath(std::string path) { path_ = path; }
+
+ amber::Result LoadBufferData(const std::string file_name,
+ amber::BufferInfo* buffer) const override {
+#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;
+#endif // AMBER_ENABLE_LODEPNG
+
+ // TODO(asuonpaa): Try to load a binary format.
+
+ return amber::Result("Failed to load buffer data " + file_name);
+ }
+
private:
bool log_graphics_calls_ = false;
bool log_graphics_calls_time_ = false;
bool log_execute_calls_ = false;
+ std::string path_ = "";
};
std::string disassemble(const std::string& env,
@@ -531,6 +550,9 @@ int main(int argc, const char** argv) {
const auto* recipe = recipe_data_elem.recipe.get();
const auto& file = recipe_data_elem.file;
+ // Parse file path and set it for delegate to use when loading buffer data.
+ delegate.SetScriptPath(file.substr(0, file.find_last_of("/\\") + 1));
+
amber::Amber am;
result = am.Execute(recipe, &amber_options);
if (!result.IsSuccess()) {
diff --git a/samples/png.cc b/samples/png.cc
index 93e2279..3dbf4fd 100644
--- a/samples/png.cc
+++ b/samples/png.cc
@@ -81,4 +81,23 @@ amber::Result ConvertToPNG(uint32_t width,
return {};
}
+amber::Result LoadPNG(const std::string file_name,
+ uint32_t* width,
+ uint32_t* height,
+ std::vector<amber::Value>* values) {
+ std::vector<uint8_t> decoded_buffer;
+ if (lodepng::decode(decoded_buffer, *width, *height, file_name,
+ LodePNGColorType::LCT_RGBA, 8) != 0) {
+ return amber::Result("lodepng::decode() returned non-zero");
+ }
+
+ for (auto d : decoded_buffer) {
+ amber::Value v;
+ v.SetIntValue(d);
+ values->push_back(v);
+ }
+
+ return {};
+}
+
} // namespace png
diff --git a/samples/png.h b/samples/png.h
index 74802e7..b08d74d 100644
--- a/samples/png.h
+++ b/samples/png.h
@@ -31,6 +31,14 @@ amber::Result ConvertToPNG(uint32_t width,
const std::vector<amber::Value>& values,
std::vector<uint8_t>* buffer);
+/// Loads a PNG image from |file_name|. Image dimensions of the loaded file are
+/// stored into |width| and |height|, and the image data is stored in a one
+/// byte per data element format into |values|.
+amber::Result LoadPNG(const std::string file_name,
+ uint32_t* width,
+ uint32_t* height,
+ std::vector<amber::Value>* values);
+
} // namespace png
#endif // SAMPLES_PNG_H_
diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc
index 8157476..60292b0 100644
--- a/src/amberscript/parser.cc
+++ b/src/amberscript/parser.cc
@@ -1224,14 +1224,27 @@ Result Parser::ParseBuffer() {
script_->RegisterFormat(std::move(fmt));
token = tokenizer_->PeekNextToken();
- if (token->IsIdentifier() && token->AsString() == "MIP_LEVELS") {
- tokenizer_->NextToken();
- token = tokenizer_->NextToken();
+ while (token->IsIdentifier()) {
+ if (token->AsString() == "MIP_LEVELS") {
+ tokenizer_->NextToken();
+ token = tokenizer_->NextToken();
- if (!token->IsInteger())
- return Result("invalid value for MIP_LEVELS");
+ if (!token->IsInteger())
+ return Result("invalid value for MIP_LEVELS");
- buffer->SetMipLevels(token->AsUint32());
+ buffer->SetMipLevels(token->AsUint32());
+ } else if (token->AsString() == "FILE") {
+ tokenizer_->NextToken();
+ token = tokenizer_->NextToken();
+
+ if (!token->IsIdentifier())
+ return Result("invalid value for FILE");
+
+ buffer->SetDataFile(token->AsString());
+ } else {
+ break;
+ }
+ token = tokenizer_->PeekNextToken();
}
} else {
return Result("unknown BUFFER command provided: " + cmd);
diff --git a/src/amberscript/parser_buffer_test.cc b/src/amberscript/parser_buffer_test.cc
index dcbd982..d2f1eb1 100644
--- a/src/amberscript/parser_buffer_test.cc
+++ b/src/amberscript/parser_buffer_test.cc
@@ -1067,5 +1067,30 @@ TEST_F(AmberScriptParserTest, BufferMissingMipLevels) {
EXPECT_EQ("1: invalid value for MIP_LEVELS", r.Error());
}
+TEST_F(AmberScriptParserTest, BufferMissingDataFile) {
+ std::string in = "BUFFER my_buffer FORMAT R8G8B8A8_UNORM FILE";
+
+ Parser parser;
+ Result r = parser.Parse(in);
+ ASSERT_FALSE(r.IsSuccess());
+
+ 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";
+
+ 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("foo.png", buffers[0]->GetDataFile());
+}
+
} // namespace amberscript
} // namespace amber
diff --git a/src/buffer.h b/src/buffer.h
index d867a5a..9d6f3d6 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -196,6 +196,12 @@ class Buffer {
/// Returns the number of mip levels.
uint32_t GetMipLevels() { return mip_levels_; }
+ /// Sets the file name for loading data into the buffer.
+ void SetDataFile(std::string data_file) { data_file_ = data_file; }
+
+ /// Returns the file name used to load buffer data from.
+ std::string GetDataFile() { return data_file_; }
+
/// 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.
@@ -252,6 +258,7 @@ class Buffer {
Format* format_ = nullptr;
Sampler* sampler_ = nullptr;
ImageDimension image_dim_ = ImageDimension::kUnknown;
+ std::string data_file_;
};
} // namespace amber
diff --git a/src/executor.cc b/src/executor.cc
index 0d428e9..5ff76d2 100644
--- a/src/executor.cc
+++ b/src/executor.cc
@@ -88,6 +88,21 @@ Result Executor::Execute(Engine* engine,
Engine::Debugger* debugger = nullptr;
+ // Load data to buffers
+ for (const auto& buf : script->GetBuffers()) {
+ if (buf->GetDataFile().empty())
+ continue;
+
+ BufferInfo info;
+ Result r = options->delegate->LoadBufferData(buf->GetDataFile(), &info);
+ if (!r.IsSuccess())
+ return r;
+
+ buf->SetData(info.values);
+ buf->SetWidth(info.width);
+ buf->SetHeight(info.height);
+ }
+
// Process Commands
for (const auto& cmd : script->GetCommands()) {
if (options->delegate && options->delegate->LogExecuteCalls()) {
diff --git a/tests/cases/draw_png_texture.amber b/tests/cases/draw_png_texture.amber
new file mode 100644
index 0000000..c7b9885
--- /dev/null
+++ b/tests/cases/draw_png_texture.amber
@@ -0,0 +1,66 @@
+#!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 vertex vert_shader_tex GLSL
+#version 430
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec2 texcoords_in;
+layout(location = 0) out vec2 texcoords_out;
+void main() {
+ gl_Position = position;
+ texcoords_out = texcoords_in;
+}
+END
+
+SHADER fragment frag_shader_tex GLSL
+#version 430
+layout(location = 0) in vec2 texcoords_in;
+layout(location = 0) out vec4 color_out;
+uniform layout(set=0, binding=0) sampler2D tex_sampler;
+void main() {
+ color_out = texture(tex_sampler, texcoords_in);
+}
+END
+
+BUFFER texture FORMAT R8G8B8A8_UNORM FILE texture.png
+BUFFER framebuffer FORMAT B8G8R8A8_UNORM
+SAMPLER sampler
+BUFFER position DATA_TYPE vec2<float> DATA
+-0.75 -0.75
+ 0.75 -0.75
+ 0.75 0.75
+-0.75 0.75
+END
+BUFFER texcoords DATA_TYPE vec2<float> DATA
+0.0 0.0
+1.0 0.0
+1.0 1.0
+0.0 1.0
+END
+
+PIPELINE graphics pipeline
+ ATTACH vert_shader_tex
+ ATTACH frag_shader_tex
+ BIND BUFFER texture AS combined_image_sampler SAMPLER sampler DESCRIPTOR_SET 0 BINDING 0
+ VERTEX_DATA position LOCATION 0
+ VERTEX_DATA texcoords LOCATION 1
+ FRAMEBUFFER_SIZE 256 256
+ BIND BUFFER framebuffer AS color LOCATION 0
+END
+
+# Draw the texture using a default sampler.
+CLEAR_COLOR pipeline 0 255 0 255
+CLEAR pipeline
+RUN pipeline DRAW_ARRAY AS TRIANGLE_FAN START_IDX 0 COUNT 4
diff --git a/tests/cases/texture.png b/tests/cases/texture.png
new file mode 100644
index 0000000..465bf9a
--- /dev/null
+++ b/tests/cases/texture.png
Binary files differ
diff --git a/tests/run_tests.py b/tests/run_tests.py
index b3903cd..6b17f56 100755
--- a/tests/run_tests.py
+++ b/tests/run_tests.py
@@ -323,7 +323,7 @@ class TestRunner:
print("--test-prog-path must point to an executable")
return 1
- input_file_re = re.compile('^.+[.][amber|vkscript]')
+ input_file_re = re.compile('^.+[\.]amber|vkscript')
self.test_cases = []
if self.args: