diff options
author | dan sinclair <dsinclair@chromium.org> | 2019-08-03 13:51:11 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-03 13:51:11 -0400 |
commit | e9e2a52ea8282b482c8e4026ed23e986c1fb6177 (patch) | |
tree | f66927b5ef85fdec9e6f4ea3553562883bc557f1 | |
parent | 5bb9c644ec17a298d901152e9a8e10f8d08c2ee3 (diff) | |
download | amber-e9e2a52ea8282b482c8e4026ed23e986c1fb6177.tar.gz |
Add root mean square error buffer comparison (#602)
This CL adds a `RMSE_BUFFER` comparator which can be used with two
buffers to verify their values are within a given tolerance using the
root mean square error comparison method.
Issue #600
-rw-r--r-- | docs/amber_script.md | 6 | ||||
-rw-r--r-- | src/amberscript/parser.cc | 55 | ||||
-rw-r--r-- | src/amberscript/parser_expect_test.cc | 188 | ||||
-rw-r--r-- | src/buffer.cc | 92 | ||||
-rw-r--r-- | src/buffer.h | 8 | ||||
-rw-r--r-- | src/command.h | 10 | ||||
-rw-r--r-- | src/executor.cc | 7 | ||||
-rw-r--r-- | src/format.h | 3 | ||||
-rw-r--r-- | tests/cases/buffer_rmse.amber | 19 | ||||
-rw-r--r-- | tests/cases/buffer_rmse_tolerance_too_large.expect_fail.amber | 20 | ||||
-rw-r--r-- | tools/amber-syntax.vim | 2 | ||||
-rw-r--r-- | tools/amber.sublime-syntax | 2 |
12 files changed, 358 insertions, 54 deletions
diff --git a/docs/amber_script.md b/docs/amber_script.md index 16d1e41..3349270 100644 --- a/docs/amber_script.md +++ b/docs/amber_script.md @@ -418,6 +418,7 @@ CLEAR {pipeline} * `EQ_RGB` * `EQ_RGBA` * `EQ_BUFFER` + * `RMSE_BUFFER` ```groovy # Checks that |buffer_name| at |x| has the given |value|s when compared @@ -446,6 +447,11 @@ EXPECT {buffer_name} IDX _x_in_pixels_ _y_in_pixels_ \ # Checks that |buffer_1| contents are equal to those of |buffer_2| EXPECT {buffer_1} EQ_BUFFER {buffer_2} + +# Checks that the Root Mean Square Error when comparing |buffer_1| to +# |buffer_2| is less than or equal too |tolerance|. Note, |tolerance| is a +# unit-less number. +EXPECT {buffer_1} RMSE_BUFFER {buffer_2} TOLERANCE _value_ ``` ## Examples diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc index de43731..8a49264 100644 --- a/src/amberscript/parser.cc +++ b/src/amberscript/parser.cc @@ -1359,6 +1359,8 @@ Result Parser::ParseExpect() { return Result("missing buffer name between EXPECT and IDX"); if (token->AsString() == "EQ_BUFFER") return Result("missing buffer name between EXPECT and EQ_BUFFER"); + if (token->AsString() == "RMSE_BUFFER") + return Result("missing buffer name between EXPECT and RMSE_BUFFER"); size_t line = tokenizer_->GetCurrentLine(); auto* buffer = script_->GetBuffer(token->AsString()); @@ -1371,44 +1373,61 @@ Result Parser::ParseExpect() { if (!token->IsString()) return Result("Invalid comparator in EXPECT command"); - if (token->AsString() == "EQ_BUFFER") { + if (token->AsString() == "EQ_BUFFER" || token->AsString() == "RMSE_BUFFER") { + auto type = token->AsString(); + token = tokenizer_->NextToken(); if (!token->IsString()) - return Result("invalid buffer name in EXPECT EQ_BUFFER command"); + return Result("invalid buffer name in EXPECT " + type + " command"); auto* buffer_2 = script_->GetBuffer(token->AsString()); if (!buffer_2) { - return Result("unknown buffer name for EXPECT EQ_BUFFER command: " + - token->AsString()); + return Result("unknown buffer name for EXPECT " + type + + " command: " + token->AsString()); } if (!buffer->GetFormat()->Equal(buffer_2->GetFormat())) { - return Result( - "EXPECT EQ_BUFFER command cannot compare buffers of differing " - "format"); + return Result("EXPECT " + type + + " 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: " + - std::to_string(buffer->ElementCount()) + " vs " + - std::to_string(buffer_2->ElementCount())); + return Result("EXPECT " + type + + " 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"); + return Result("EXPECT " + type + + " command cannot compare buffers of different width"); } if (buffer->GetHeight() != buffer_2->GetHeight()) { - return Result( - "EXPECT EQ_BUFFER command cannot compare buffers of different " - "height"); + return Result("EXPECT " + type + + " command cannot compare buffers of different height"); } auto cmd = MakeUnique<CompareBufferCommand>(buffer, buffer_2); + if (type == "RMSE_BUFFER") { + cmd->SetComparator(CompareBufferCommand::Comparator::kRmse); + + token = tokenizer_->NextToken(); + if (!token->IsString() && token->AsString() == "TOLERANCE") + return Result("Missing TOLERANCE for EXPECT RMSE_BUFFER"); + + token = tokenizer_->NextToken(); + if (!token->IsInteger() && !token->IsDouble()) + return Result("Invalid TOLERANCE for EXPECT RMSE_BUFFER"); + + Result r = token->ConvertToDouble(); + if (!r.IsSuccess()) + return r; + + cmd->SetTolerance(token->AsFloat()); + } + command_list_.push_back(std::move(cmd)); // Early return - return ValidateEndOfStatement("EXPECT EQ_BUFFER command"); + return ValidateEndOfStatement("EXPECT " + type + " command"); } if (token->AsString() != "IDX") diff --git a/src/amberscript/parser_expect_test.cc b/src/amberscript/parser_expect_test.cc index 7bb03e3..0c345a7 100644 --- a/src/amberscript/parser_expect_test.cc +++ b/src/amberscript/parser_expect_test.cc @@ -687,8 +687,7 @@ BUFFER orig_buf DATA_TYPE int32 SIZE 100 FILL 11 BUFFER dest_buf DATA_TYPE int32 SIZE 100 FILL 22 EXPECT orig_buf IDX 0 EQ 11 -EXPECT dest_buf IDX 0 EQ 22 -)"; +EXPECT dest_buf IDX 0 EQ 22)"; Parser parser; Result r = parser.Parse(in); @@ -699,69 +698,74 @@ TEST_F(AmberScriptParserTest, ExpectEqBuffer) { std::string in = R"( BUFFER buf_1 DATA_TYPE int32 SIZE 10 FILL 11 BUFFER buf_2 DATA_TYPE int32 SIZE 10 FILL 11 - -EXPECT buf_1 EQ_BUFFER buf_2 -)"; +EXPECT buf_1 EQ_BUFFER buf_2)"; Parser parser; Result r = parser.Parse(in); ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& commands = script->GetCommands(); + ASSERT_EQ(1U, commands.size()); + + auto* cmd = commands[0].get(); + ASSERT_TRUE(cmd->IsCompareBuffer()); + + auto* cmp = cmd->AsCompareBuffer(); + EXPECT_EQ(cmp->GetComparator(), CompareBufferCommand::Comparator::kEq); + + ASSERT_TRUE(cmp->GetBuffer1() != nullptr); + EXPECT_EQ(cmp->GetBuffer1()->GetName(), "buf_1"); + + ASSERT_TRUE(cmp->GetBuffer2() != nullptr); + EXPECT_EQ(cmp->GetBuffer2()->GetName(), "buf_2"); } TEST_F(AmberScriptParserTest, ExpectEqBufferMissingFirstBuffer) { std::string in = R"( BUFFER buf_2 DATA_TYPE int32 SIZE 10 FILL 22 - -EXPECT EQ_BUFFER buf_2 -)"; +EXPECT EQ_BUFFER buf_2)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()); - EXPECT_EQ("4: missing buffer name between EXPECT and EQ_BUFFER", r.Error()); + EXPECT_EQ("3: missing buffer name between EXPECT and EQ_BUFFER", r.Error()); } TEST_F(AmberScriptParserTest, ExpectEqBufferMissingSecondBuffer) { std::string in = R"( BUFFER buf_1 DATA_TYPE int32 SIZE 10 FILL 11 - -EXPECT buf_1 EQ_BUFFER -)"; +EXPECT buf_1 EQ_BUFFER)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()); - EXPECT_EQ("5: invalid buffer name in EXPECT EQ_BUFFER command", r.Error()); + EXPECT_EQ("3: invalid buffer name in EXPECT EQ_BUFFER command", r.Error()); } TEST_F(AmberScriptParserTest, ExpectEqBufferInvalidFirstBuffer) { - std::string in = R"( -EXPECT 123 EQ_BUFFER -)"; + std::string in = R"(EXPECT 123 EQ_BUFFER)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()); - EXPECT_EQ("2: invalid buffer name in EXPECT command", r.Error()); + EXPECT_EQ("1: invalid buffer name in EXPECT command", r.Error()); } TEST_F(AmberScriptParserTest, ExpectEqBufferUnknownFirstBuffer) { - std::string in = R"( -EXPECT unknown_buffer EQ_BUFFER -)"; + std::string in = R"(EXPECT unknown_buffer EQ_BUFFER)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()); - EXPECT_EQ("2: unknown buffer name for EXPECT command: unknown_buffer", + EXPECT_EQ("1: unknown buffer name for EXPECT command: unknown_buffer", r.Error()); } TEST_F(AmberScriptParserTest, ExpectEqBufferInvalidSecondBuffer) { std::string in = R"( BUFFER buf DATA_TYPE int32 SIZE 10 FILL 11 -EXPECT buf EQ_BUFFER 123 -)"; +EXPECT buf EQ_BUFFER 123)"; Parser parser; Result r = parser.Parse(in); @@ -772,8 +776,7 @@ EXPECT buf EQ_BUFFER 123 TEST_F(AmberScriptParserTest, ExpectEqBufferUnknownSecondBuffer) { std::string in = R"( BUFFER buf DATA_TYPE int32 SIZE 10 FILL 11 -EXPECT buf EQ_BUFFER unknown_buffer -)"; +EXPECT buf EQ_BUFFER unknown_buffer)"; Parser parser; Result r = parser.Parse(in); @@ -787,15 +790,13 @@ TEST_F(AmberScriptParserTest, ExpectEqBufferDifferentSize) { std::string in = R"( BUFFER buf_1 DATA_TYPE int32 SIZE 10 FILL 11 BUFFER buf_2 DATA_TYPE int32 SIZE 99 FILL 11 - -EXPECT buf_1 EQ_BUFFER buf_2 -)"; +EXPECT buf_1 EQ_BUFFER buf_2)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()); EXPECT_EQ( - "5: EXPECT EQ_BUFFER command cannot compare buffers of different size: " + "4: EXPECT EQ_BUFFER command cannot compare buffers of different size: " "10 vs 99", r.Error()); } @@ -804,15 +805,13 @@ TEST_F(AmberScriptParserTest, ExpectEqBufferDifferentType) { std::string in = R"( BUFFER buf_1 DATA_TYPE int32 SIZE 10 FILL 11 BUFFER buf_2 FORMAT R32G32B32A32_SFLOAT - -EXPECT buf_1 EQ_BUFFER buf_2 -)"; +EXPECT buf_1 EQ_BUFFER buf_2)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()); EXPECT_EQ( - "5: EXPECT EQ_BUFFER command cannot compare buffers of differing format", + "4: EXPECT EQ_BUFFER command cannot compare buffers of differing format", r.Error()); } @@ -949,5 +948,128 @@ EXPECT orig_buf IDX 5 TOLERANCE 1 2 3 4 NE 11)"; EXPECT_EQ("3: TOLERANCE only available with EQ probes", r.Error()); } +TEST_F(AmberScriptParserTest, ExpectRMSEBuffer) { + std::string in = R"( +BUFFER buf_1 DATA_TYPE int32 SIZE 10 FILL 11 +BUFFER buf_2 DATA_TYPE int32 SIZE 10 FILL 12 +EXPECT buf_1 RMSE_BUFFER buf_2 TOLERANCE 0.1)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& commands = script->GetCommands(); + ASSERT_EQ(1U, commands.size()); + + auto* cmd = commands[0].get(); + ASSERT_TRUE(cmd->IsCompareBuffer()); + + auto* cmp = cmd->AsCompareBuffer(); + EXPECT_EQ(cmp->GetComparator(), CompareBufferCommand::Comparator::kRmse); + EXPECT_FLOAT_EQ(cmp->GetTolerance(), 0.1f); + + ASSERT_TRUE(cmp->GetBuffer1() != nullptr); + EXPECT_EQ(cmp->GetBuffer1()->GetName(), "buf_1"); + + ASSERT_TRUE(cmp->GetBuffer2() != nullptr); + EXPECT_EQ(cmp->GetBuffer2()->GetName(), "buf_2"); +} + +TEST_F(AmberScriptParserTest, ExpectRMSEBufferMissingFirstBuffer) { + std::string in = R"( +BUFFER buf_2 DATA_TYPE int32 SIZE 10 FILL 22 +EXPECT RMSE_BUFFER buf_2)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("3: missing buffer name between EXPECT and RMSE_BUFFER", r.Error()); +} + +TEST_F(AmberScriptParserTest, ExpectRMSEBufferMissingSecondBuffer) { + std::string in = R"( +BUFFER buf_1 DATA_TYPE int32 SIZE 10 FILL 11 +EXPECT buf_1 RMSE_BUFFER)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("3: invalid buffer name in EXPECT RMSE_BUFFER command", r.Error()); +} + +TEST_F(AmberScriptParserTest, ExpectRMSEBufferInvalidFirstBuffer) { + std::string in = R"(EXPECT 123 RMSE_BUFFER)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("1: invalid buffer name in EXPECT command", r.Error()); +} + +TEST_F(AmberScriptParserTest, ExpectRMSEBufferUnknownFirstBuffer) { + std::string in = R"(EXPECT unknown_buffer RMSE_BUFFER)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("1: unknown buffer name for EXPECT command: unknown_buffer", + r.Error()); +} + +TEST_F(AmberScriptParserTest, ExpectRMSEBufferInvalidSecondBuffer) { + std::string in = R"( +BUFFER buf DATA_TYPE int32 SIZE 10 FILL 11 +EXPECT buf RMSE_BUFFER 123)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("3: invalid buffer name in EXPECT RMSE_BUFFER command", r.Error()); +} + +TEST_F(AmberScriptParserTest, ExpectRMSEBufferUnknownSecondBuffer) { + std::string in = R"( +BUFFER buf DATA_TYPE int32 SIZE 10 FILL 11 +EXPECT buf RMSE_BUFFER unknown_buffer)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ( + "3: unknown buffer name for EXPECT RMSE_BUFFER command: unknown_buffer", + r.Error()); +} + +TEST_F(AmberScriptParserTest, ExpectRMSEBufferDifferentSize) { + std::string in = R"( +BUFFER buf_1 DATA_TYPE int32 SIZE 10 FILL 11 +BUFFER buf_2 DATA_TYPE int32 SIZE 99 FILL 11 +EXPECT buf_1 RMSE_BUFFER buf_2)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ( + "4: EXPECT RMSE_BUFFER command cannot compare buffers of different size: " + "10 vs 99", + r.Error()); +} + +TEST_F(AmberScriptParserTest, ExpectRMSEBufferDifferentType) { + std::string in = R"( +BUFFER buf_1 DATA_TYPE int32 SIZE 10 FILL 11 +BUFFER buf_2 FORMAT R32G32B32A32_SFLOAT +EXPECT buf_1 RMSE_BUFFER buf_2)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ( + "4: EXPECT RMSE_BUFFER command cannot compare buffers of differing " + "format", + r.Error()); +} + } // namespace amberscript } // namespace amber diff --git a/src/buffer.cc b/src/buffer.cc index 617ff7a..f160923 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -15,6 +15,7 @@ #include "src/buffer.h" #include <cassert> +#include <cmath> #include <cstring> namespace amber { @@ -53,6 +54,45 @@ T* ValuesAs(uint8_t* values) { return reinterpret_cast<T*>(values); } +template <typename T> +double Sub(const uint8_t* buf1, const uint8_t* buf2) { + return static_cast<double>(*reinterpret_cast<const T*>(buf1) - + *reinterpret_cast<const T*>(buf2)); +} + +double CalculateDiff(const Format::Component& comp, + const uint8_t* buf1, + const uint8_t* buf2) { + if (comp.IsInt8()) + return Sub<int8_t>(buf1, buf2); + if (comp.IsInt16()) + return Sub<int16_t>(buf1, buf2); + if (comp.IsInt32()) + return Sub<int32_t>(buf1, buf2); + if (comp.IsInt64()) + return Sub<int64_t>(buf1, buf2); + if (comp.IsUint8()) + return Sub<uint8_t>(buf1, buf2); + if (comp.IsUint16()) + return Sub<uint16_t>(buf1, buf2); + if (comp.IsUint32()) + return Sub<uint32_t>(buf1, buf2); + if (comp.IsUint64()) + return Sub<uint64_t>(buf1, buf2); + // TOOD(dsinclair): Handle float16 ... + if (comp.IsFloat16()) { + assert(false && "Float16 suppport not implemented"); + return 0.0; + } + if (comp.IsFloat()) + return Sub<float>(buf1, buf2); + if (comp.IsDouble()) + return Sub<double>(buf1, buf2); + + assert(false && "NOTREACHED"); + return 0.0; +} + } // namespace Buffer::Buffer() = default; @@ -111,6 +151,58 @@ Result Buffer::IsEqual(Buffer* buffer) const { return {}; } +std::vector<double> Buffer::CalculateDiffs(const Buffer* buffer) const { + std::vector<double> diffs; + + auto* buf_1_ptr = GetValues<uint8_t>(); + auto* buf_2_ptr = buffer->GetValues<uint8_t>(); + auto comps = format_->GetComponents(); + + for (size_t i = 0; i < ElementCount(); ++i) { + for (size_t j = 0; j < format_->ColumnCount(); ++j) { + auto* buf_1_row_ptr = buf_1_ptr; + auto* buf_2_row_ptr = buf_2_ptr; + for (size_t k = 0; k < format_->RowCount(); ++k) { + diffs.push_back(CalculateDiff(comps[k], buf_1_row_ptr, buf_2_row_ptr)); + + buf_1_row_ptr += comps[k].SizeInBytes(); + buf_2_row_ptr += comps[k].SizeInBytes(); + } + buf_1_ptr += format_->SizeInBytesPerRow(); + buf_2_ptr += format_->SizeInBytesPerRow(); + } + } + + return diffs; +} + +Result Buffer::CompareRMSE(Buffer* buffer, float tolerance) const { + 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_) + return Result{"Buffers have a different width"}; + if (buffer->height_ != height_) + return Result{"Buffers have a different height"}; + if (buffer->ValueCount() != ValueCount()) + return Result{"Buffers have a different number of values"}; + + auto diffs = CalculateDiffs(buffer); + double sum = 0.0; + for (const auto val : diffs) + sum += (val * val); + + sum /= diffs.size(); + double rmse = std::sqrt(sum); + if (rmse > static_cast<double>(tolerance)) { + return Result("Root Mean Square Error of " + std::to_string(rmse) + + " is greater then tolerance of " + std::to_string(tolerance)); + } + + return {}; +} + Result Buffer::SetData(const std::vector<Value>& data) { return SetDataWithOffset(data, 0); } diff --git a/src/buffer.h b/src/buffer.h index 906454d..c9b1db9 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -193,11 +193,19 @@ class Buffer { /// Succeeds only if both buffer contents are equal Result IsEqual(Buffer* buffer) const; + /// Compare the RMSE of this buffer against |buffer|. The RMSE must be + /// less than |tolerance|. + Result CompareRMSE(Buffer* buffer, float tolerance) const; + private: uint32_t WriteValueFromComponent(const Value& value, const Format::Component& comp, uint8_t* ptr); + // Calculates the difference between the value stored in this buffer and + // those stored in |buffer| and returns all the values. + std::vector<double> CalculateDiffs(const Buffer* buffer) const; + BufferType buffer_type_ = BufferType::kUnknown; std::string name_; /// max_size_in_bytes_ is the total size in bytes needed to hold the buffer diff --git a/src/command.h b/src/command.h index 24fde27..f10f8fe 100644 --- a/src/command.h +++ b/src/command.h @@ -212,17 +212,27 @@ class DrawArraysCommand : public PipelineCommand { /// A command to compare two buffers. class CompareBufferCommand : public Command { public: + enum class Comparator { kEq, kRmse }; + CompareBufferCommand(Buffer* buffer_1, Buffer* buffer_2); ~CompareBufferCommand() override; Buffer* GetBuffer1() const { return buffer_1_; } Buffer* GetBuffer2() const { return buffer_2_; } + void SetComparator(Comparator type) { comparator_ = type; } + Comparator GetComparator() const { return comparator_; } + + void SetTolerance(float tolerance) { tolerance_ = tolerance; } + float GetTolerance() const { return tolerance_; } + std::string ToString() const override { return "CompareBufferCommand"; } private: Buffer* buffer_1_; Buffer* buffer_2_; + float tolerance_ = 0.0; + Comparator comparator_ = Comparator::kEq; }; /// Command to execute a compute command. diff --git a/src/executor.cc b/src/executor.cc index f3c829f..3cd67c3 100644 --- a/src/executor.cc +++ b/src/executor.cc @@ -125,7 +125,12 @@ Result Executor::ExecuteCommand(Engine* engine, Command* cmd) { auto compare = cmd->AsCompareBuffer(); auto buffer_1 = compare->GetBuffer1(); auto buffer_2 = compare->GetBuffer2(); - return buffer_1->IsEqual(buffer_2); + switch (compare->GetComparator()) { + case CompareBufferCommand::Comparator::kRmse: + return buffer_1->CompareRMSE(buffer_2, compare->GetTolerance()); + case CompareBufferCommand::Comparator::kEq: + return buffer_1->IsEqual(buffer_2); + } } if (cmd->IsCopy()) { auto copy = cmd->AsCopy(); diff --git a/src/format.h b/src/format.h index 0888a43..d4dbe04 100644 --- a/src/format.h +++ b/src/format.h @@ -45,6 +45,9 @@ class Format { FormatMode mode; uint8_t num_bits; + /// Returns the number of bytes used to store this component. + size_t SizeInBytes() const { return num_bits / 8; } + /// Is this component represented by an 8 bit signed integer. (This includes /// int, scaled, rgb and norm values). bool IsInt8() const { diff --git a/tests/cases/buffer_rmse.amber b/tests/cases/buffer_rmse.amber new file mode 100644 index 0000000..bad1aa5 --- /dev/null +++ b/tests/cases/buffer_rmse.amber @@ -0,0 +1,19 @@ +#!amber +# 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 +# +# 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. + +BUFFER in_buf DATA_TYPE float DATA 1.1 2.2 3.3 4.4 END +BUFFER out_buf DATA_TYPE float DATA 1.0 2.1 3.2 4.3 END + +EXPECT in_buf RMSE_BUFFER out_buf TOLERANCE 0.1 diff --git a/tests/cases/buffer_rmse_tolerance_too_large.expect_fail.amber b/tests/cases/buffer_rmse_tolerance_too_large.expect_fail.amber new file mode 100644 index 0000000..af5a5fa --- /dev/null +++ b/tests/cases/buffer_rmse_tolerance_too_large.expect_fail.amber @@ -0,0 +1,20 @@ +#!amber +# 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 +# +# 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. + +BUFFER in_buf DATA_TYPE float DATA 1.1 2.2 3.3 4.4 END +BUFFER out_buf DATA_TYPE float DATA 1.0 2.1 3.2 4.3 END + +EXPECT in_buf RMSE_BUFFER out_buf TOLERANCE 0.01 + diff --git a/tools/amber-syntax.vim b/tools/amber-syntax.vim index 0d47c6c..b474cb7 100644 --- a/tools/amber-syntax.vim +++ b/tools/amber-syntax.vim @@ -38,7 +38,7 @@ syn keyword amberBlockCmd VERTEX_DATA INDEX_DATA INDEXED IMAGE_ATTACHMENT syn keyword amberBlockCmd DEPTH_STENCIL_ATTACHMENT DEVICE_FEATURE TOLERANCE syn keyword amberBlockCmd REPEAT COPY DERIVE_PIPELINE FROM -syn keyword amberComparator EQ NE LT LE GT GE EQ_RGB EQ_RGBA EQ_BUFFER +syn keyword amberComparator EQ NE LT LE GT GE EQ_RGB EQ_RGBA EQ_BUFFER RMSE_BUFFER syn keyword amberKeyword compute vertex geometry fragment graphics syn keyword amberKeyword tessellation_evaulation tessellation_control multi diff --git a/tools/amber.sublime-syntax b/tools/amber.sublime-syntax index 92ac566..8fe18ff 100644 --- a/tools/amber.sublime-syntax +++ b/tools/amber.sublime-syntax @@ -40,7 +40,7 @@ contexts: scope: constant.character.escape.amber - match: '\b(uniform|storage|push_constant|color|depth_stencil)\b' scope: constant.character.escape.amber - - match: '\b(EQ|NE|LT|LE|GT|GE|EQ_RGB|EQ_RGBA|EQ_BUFFER)\b' + - match: '\b(EQ|NE|LT|LE|GT|GE|EQ_RGB|EQ_RGBA|EQ_BUFFER|RMSE_BUFFER)\b' scope: constant.character.esape.amber - match: '\b(GLSL|HLSL|SPIRV-ASM|SPIRV-HEX|OPENCL-C)\b' scope: constant.character.escape.amber |