diff options
author | dan sinclair <dsinclair@google.com> | 2019-10-10 14:13:14 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-10 14:13:14 -0400 |
commit | bfd82bec68975d552abbbc0f6aa69857d3f53baa (patch) | |
tree | 1ff974379c382ae4460fd69884a61fdb90556d64 /src | |
parent | ab41eacc3fba9ea3365a57b1712837cb4ed6d2c4 (diff) | |
download | amber-bfd82bec68975d552abbbc0f6aa69857d3f53baa.tar.gz |
New type structure (#679)
This CL replaces the Format;:Components with a new Type hierarchy in
Amber. This allows more flexibility in defining how types are created.
Fixes #603
Diffstat (limited to 'src')
32 files changed, 3432 insertions, 1180 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 76c6f12..1bb94a2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,7 +22,6 @@ set(AMBER_SOURCES engine.cc executor.cc format.cc - format_parser.cc parser.cc pipeline.cc pipeline_data.cc @@ -33,6 +32,8 @@ set(AMBER_SOURCES shader.cc shader_compiler.cc tokenizer.cc + type.cc + type_parser.cc value.cc verifier.cc vkscript/command_parser.cc @@ -134,13 +135,14 @@ if (${AMBER_ENABLE_TESTS}) command_data_test.cc descriptor_set_and_binding_parser_test.cc executor_test.cc - format_parser_test.cc format_test.cc pipeline_test.cc result_test.cc script_test.cc shader_compiler_test.cc tokenizer_test.cc + type_parser_test.cc + type_test.cc verifier_test.cc vkscript/command_parser_test.cc vkscript/datum_type_parser_test.cc diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc index 9c8a300..92cfbfa 100644 --- a/src/amberscript/parser.cc +++ b/src/amberscript/parser.cc @@ -20,19 +20,15 @@ #include <utility> #include <vector> -#include "src/format_parser.h" #include "src/make_unique.h" #include "src/shader_data.h" #include "src/tokenizer.h" +#include "src/type_parser.h" namespace amber { namespace amberscript { namespace { -FormatComponentType FORMAT_TYPES[] = { - FormatComponentType::kR, FormatComponentType::kG, FormatComponentType::kB, - FormatComponentType::kA}; - bool IsComparator(const std::string& in) { return in == "EQ" || in == "NE" || in == "GT" || in == "LT" || in == "GE" || in == "LE"; @@ -54,32 +50,30 @@ ProbeSSBOCommand::Comparator ToComparator(const std::string& in) { return ProbeSSBOCommand::Comparator::kLessOrEqual; } -std::unique_ptr<Format> ToFormat(const std::string& str) { - std::unique_ptr<Format> fmt; - bool matrix = false; - - FormatParser fp; - if (str == "int8") { - fmt = fp.Parse("R8_SINT"); - } else if (str == "int16") { - fmt = fp.Parse("R16_SINT"); - } else if (str == "int32") { - fmt = fp.Parse("R32_SINT"); - } else if (str == "int64") { - fmt = fp.Parse("R64_SINT"); - } else if (str == "uint8") { - fmt = fp.Parse("R8_UINT"); - } else if (str == "uint16") { - fmt = fp.Parse("R16_UINT"); - } else if (str == "uint32") { - fmt = fp.Parse("R32_UINT"); - } else if (str == "uint64") { - fmt = fp.Parse("R64_UINT"); - } else if (str == "float") { - fmt = fp.Parse("R32_SFLOAT"); - } else if (str == "double") { - fmt = fp.Parse("R64_SFLOAT"); - } else if (str.length() > 7 && str.substr(0, 3) == "vec") { +std::unique_ptr<type::Type> ToType(const std::string& str) { + TypeParser parser; + if (str == "int8") + return parser.Parse("R8_SINT"); + if (str == "int16") + return parser.Parse("R16_SINT"); + if (str == "int32") + return parser.Parse("R32_SINT"); + if (str == "int64") + return parser.Parse("R64_SINT"); + if (str == "uint8") + return parser.Parse("R8_UINT"); + if (str == "uint16") + return parser.Parse("R16_UINT"); + if (str == "uint32") + return parser.Parse("R32_UINT"); + if (str == "uint64") + return parser.Parse("R64_UINT"); + if (str == "float") + return parser.Parse("R32_SFLOAT"); + if (str == "double") + return parser.Parse("R64_SFLOAT"); + + if (str.length() > 7 && str.substr(0, 3) == "vec") { if (str[4] != '<' || str[str.length() - 1] != '>') return nullptr; @@ -87,25 +81,23 @@ std::unique_ptr<Format> ToFormat(const std::string& str) { if (component_count < 2 || component_count > 4) return nullptr; - auto sub_fmt = ToFormat(str.substr(5, str.length() - 6)); - if (!sub_fmt) + auto type = ToType(str.substr(5, str.length() - 6)); + if (!type) return nullptr; - if (sub_fmt->RowCount() != 1 || sub_fmt->ColumnCount() != 1) + if (!type->IsNumber() || type->IsArray() || type->IsVec() || + type->IsMatrix()) { return nullptr; + } - fmt = MakeUnique<Format>(); - const auto* comp = sub_fmt->GetOnlyComponent(); - // TODO(dsinclair): Make sure this isn't a struct. - for (int i = 0; i < component_count; ++i) - fmt->AddComponent(FORMAT_TYPES[i], comp->mode, comp->num_bits); + type->SetRowCount(static_cast<uint32_t>(component_count)); + return type; + } - } else if (str.length() > 9 && str.substr(0, 3) == "mat") { + if (str.length() > 9 && str.substr(0, 3) == "mat") { if (str[4] != 'x' || str[6] != '<' || str[str.length() - 1] != '>') return nullptr; - matrix = true; - int column_count = str[3] - '0'; if (column_count < 2 || column_count > 4) return nullptr; @@ -114,38 +106,19 @@ std::unique_ptr<Format> ToFormat(const std::string& str) { if (row_count < 2 || row_count > 4) return nullptr; - auto sub_fmt = ToFormat(str.substr(7, str.length() - 8)); - if (!sub_fmt) + auto type = ToType(str.substr(7, str.length() - 8)); + if (!type) return nullptr; - - if (sub_fmt->RowCount() != 1 || sub_fmt->ColumnCount() != 1) - return nullptr; - - fmt = MakeUnique<Format>(); - fmt->SetColumnCount(static_cast<uint32_t>(column_count)); - - const auto* comp = sub_fmt->GetOnlyComponent(); - // TODO(dsinclair): Make sure this isn't a struct. - for (int i = 0; i < row_count; ++i) - fmt->AddComponent(FORMAT_TYPES[i], comp->mode, comp->num_bits); - - } else { - return nullptr; - } - - // Convert the name back into a FormatType so we can use it in the buffer - // later Otherwise, we end up with a type of Unknown. - // - // There is no equivalent type for a matrix. - if (!matrix) { - std::string name = fmt->GenerateName(); - if (name == "") + if (!type->IsNumber() || type->IsArray() || type->IsVec() || + type->IsMatrix()) { return nullptr; + } - fmt->SetFormatType(FormatParser::NameToType(name)); + type->SetRowCount(static_cast<uint32_t>(row_count)); + type->SetColumnCount(static_cast<uint32_t>(column_count)); + return type; } - - return fmt; + return nullptr; } } // namespace @@ -206,10 +179,10 @@ Result Parser::Parse(const std::string& data) { if (pipeline->GetColorAttachments().empty()) { auto* buf = script_->GetBuffer(Pipeline::kGeneratedColorBuffer); if (!buf) { - auto new_buf = pipeline->GenerateDefaultColorAttachmentBuffer(); - buf = new_buf.get(); + auto color_buf = pipeline->GenerateDefaultColorAttachmentBuffer(); + buf = color_buf.get(); - Result r = script_->AddBuffer(std::move(new_buf)); + Result r = script_->AddBuffer(std::move(color_buf)); if (!r.IsSuccess()) return r; } @@ -546,15 +519,20 @@ Result Parser::ParseShaderSpecialization(Pipeline* pipeline) { if (!token->IsString()) return Result("expected data type in SPECIALIZE subcommand"); - auto fmt = ToFormat(token->AsString()); - if (!fmt) + auto type = ToType(token->AsString()); + if (!type) return Result("invalid data_type provided"); + if (!type->IsNumber()) + return Result("only numeric types are accepted for specialization values"); + + auto num = type->AsNumber(); token = tokenizer_->NextToken(); uint32_t value = 0; - if (fmt->IsUint32() || fmt->IsInt32()) { + if (type::Type::IsUint32(num->GetFormatMode(), num->NumBits()) || + type::Type::IsInt32(num->GetFormatMode(), num->NumBits())) { value = token->AsUint32(); - } else if (fmt->IsFloat()) { + } else if (type::Type::IsFloat32(num->GetFormatMode(), num->NumBits())) { Result r = token->ConvertToDouble(); if (!r.IsSuccess()) return Result("value is not a floating point value"); @@ -870,16 +848,17 @@ Result Parser::ParsePipelineSet(Pipeline* pipeline) { if (!token->IsString()) return Result("expected data type"); - auto fmt = ToFormat(token->AsString()); - if (!fmt) + auto type = ToType(token->AsString()); + if (!type) return Result("invalid data_type provided"); token = tokenizer_->NextToken(); if (!token->IsInteger() && !token->IsDouble()) return Result("expected data value"); + auto fmt = MakeUnique<Format>(type.get()); Value value; - if (fmt->IsFloat() || fmt->IsDouble()) + if (fmt->IsFloat32() || fmt->IsFloat64()) value.SetDoubleValue(token->AsDouble()); else value.SetIntValue(token->AsUint64()); @@ -891,6 +870,7 @@ Result Parser::ParsePipelineSet(Pipeline* pipeline) { info.value = value; pipeline->SetArg(std::move(info)); script_->RegisterFormat(std::move(fmt)); + script_->RegisterType(std::move(type)); return ValidateEndOfStatement("SET command"); } @@ -923,13 +903,15 @@ Result Parser::ParseBuffer() { buffer = MakeUnique<Buffer>(); - FormatParser fmt_parser; - auto fmt = fmt_parser.Parse(token->AsString()); - if (fmt == nullptr) + TypeParser type_parser; + auto type = type_parser.Parse(token->AsString()); + if (type == nullptr) return Result("invalid BUFFER FORMAT"); + auto fmt = MakeUnique<Format>(type.get()); buffer->SetFormat(fmt.get()); script_->RegisterFormat(std::move(fmt)); + script_->RegisterType(std::move(type)); } else { return Result("unknown BUFFER command provided: " + cmd); } @@ -947,18 +929,22 @@ Result Parser::ParseBufferInitializer(Buffer* buffer) { if (!token->IsString()) return Result("BUFFER invalid data type"); - FormatParser fp; - auto fmt = fp.Parse(token->AsString()); - if (fmt != nullptr) { + TypeParser parser; + auto type = parser.Parse(token->AsString()); + std::unique_ptr<Format> fmt; + if (type != nullptr) { + fmt = MakeUnique<Format>(type.get()); buffer->SetFormat(fmt.get()); } else { - fmt = ToFormat(token->AsString()); - if (!fmt) + type = ToType(token->AsString()); + if (!type) return Result("invalid data_type provided"); + fmt = MakeUnique<Format>(type.get()); buffer->SetFormat(fmt.get()); } script_->RegisterFormat(std::move(fmt)); + script_->RegisterType(std::move(type)); token = tokenizer_->NextToken(); if (!token->IsString()) @@ -1014,7 +1000,7 @@ Result Parser::ParseBufferInitializerFill(Buffer* buffer, return Result("invalid BUFFER fill value"); auto fmt = buffer->GetFormat(); - bool is_double_data = fmt->IsFloat() || fmt->IsDouble(); + bool is_double_data = fmt->IsFloat32() || fmt->IsFloat64(); // Inflate the size because our items are multi-dimensional. size_in_items = size_in_items * fmt->InputNeededPerElement(); @@ -1042,17 +1028,21 @@ Result Parser::ParseBufferInitializerSeries(Buffer* buffer, if (!token->IsInteger() && !token->IsDouble()) return Result("invalid BUFFER series_from value"); - auto fmt = buffer->GetFormat(); - if (fmt->RowCount() > 1 || fmt->ColumnCount() > 1) + auto type = buffer->GetFormat()->GetType(); + if (type->IsMatrix() || type->IsVec()) return Result("BUFFER series_from must not be multi-row/column types"); - bool is_double_data = fmt->IsFloat() || fmt->IsDouble(); - Value counter; - if (is_double_data) + + auto n = type->AsNumber(); + FormatMode mode = n->GetFormatMode(); + uint32_t num_bits = n->NumBits(); + if (type::Type::IsFloat32(mode, num_bits) || + type::Type::IsFloat64(mode, num_bits)) { counter.SetDoubleValue(token->AsDouble()); - else + } else { counter.SetIntValue(token->AsUint64()); + } token = tokenizer_->NextToken(); if (!token->IsString()) @@ -1069,7 +1059,8 @@ Result Parser::ParseBufferInitializerSeries(Buffer* buffer, std::vector<Value> values; values.resize(size_in_items); for (size_t i = 0; i < size_in_items; ++i) { - if (is_double_data) { + if (type::Type::IsFloat32(mode, num_bits) || + type::Type::IsFloat64(mode, num_bits)) { double value = counter.AsDouble(); values[i].SetDoubleValue(value); counter.SetDoubleValue(value + token->AsDouble()); @@ -1088,7 +1079,7 @@ Result Parser::ParseBufferInitializerSeries(Buffer* buffer, Result Parser::ParseBufferInitializerData(Buffer* buffer) { auto fmt = buffer->GetFormat(); - bool is_double_type = fmt->IsFloat() || fmt->IsDouble(); + bool is_double_type = fmt->IsFloat32() || fmt->IsFloat64(); std::vector<Value> values; for (auto token = tokenizer_->NextToken();; token = tokenizer_->NextToken()) { @@ -1358,7 +1349,7 @@ Result Parser::ParseValues(const std::string& name, while (!token->IsEOL() && !token->IsEOS()) { Value v; - if (fmt->IsFloat() || fmt->IsDouble()) { + if (fmt->IsFloat32() || fmt->IsFloat64()) { if (!token->IsInteger() && !token->IsDouble()) { return Result(std::string("Invalid value provided to ") + name + " command: " + token->ToOriginalString()); diff --git a/src/amberscript/parser_buffer_test.cc b/src/amberscript/parser_buffer_test.cc index 1826af5..a0aa357 100644 --- a/src/amberscript/parser_buffer_test.cc +++ b/src/amberscript/parser_buffer_test.cc @@ -105,7 +105,7 @@ END)"; EXPECT_EQ("my_buffer", buffers[0]->GetName()); auto* buffer = buffers[0].get(); - EXPECT_TRUE(buffer->GetFormat()->IsFloat()); + EXPECT_TRUE(buffer->GetFormat()->IsFloat32()); EXPECT_EQ(Format::Layout::kStd430, buffer->GetFormat()->GetLayout()); EXPECT_EQ(1U, buffer->ElementCount()); EXPECT_EQ(4U, buffer->ValueCount()); @@ -138,15 +138,14 @@ END)"; EXPECT_EQ("my_buffer", buffers[0]->GetName()); auto* buffer = buffers[0].get(); - EXPECT_TRUE(buffer->GetFormat()->IsFloat()); + EXPECT_TRUE(buffer->GetFormat()->IsFloat32()); EXPECT_EQ(Format::Layout::kStd140, buffer->GetFormat()->GetLayout()); EXPECT_EQ(1U, buffer->ElementCount()); - EXPECT_EQ(8U, buffer->ValueCount()); + EXPECT_EQ(4U, buffer->ValueCount()); EXPECT_EQ(8U * sizeof(float), buffer->GetSizeInBytes()); std::vector<float> results = {1.f, 2.f, 0.f, 0.f, 3.f, 4.f, 0.f, 0.f}; const auto* data = buffer->GetValues<float>(); - ASSERT_EQ(results.size(), buffer->ValueCount()); for (size_t i = 0; i < results.size(); ++i) { EXPECT_FLOAT_EQ(results[i], data[i]); } @@ -229,7 +228,7 @@ TEST_F(AmberScriptParserTest, BufferDataFloat) { EXPECT_EQ("my_buffer", buffers[0]->GetName()); auto* buffer = buffers[0].get(); - EXPECT_TRUE(buffer->GetFormat()->IsFloat()); + EXPECT_TRUE(buffer->GetFormat()->IsFloat32()); EXPECT_EQ(Format::Layout::kStd430, buffer->GetFormat()->GetLayout()); EXPECT_EQ(4U, buffer->ElementCount()); EXPECT_EQ(4U, buffer->ValueCount()); @@ -287,7 +286,7 @@ TEST_F(AmberScriptParserTest, BufferFillFloat) { auto* buffer = buffers[0].get(); EXPECT_EQ("my_buffer", buffer->GetName()); - EXPECT_TRUE(buffer->GetFormat()->IsFloat()); + EXPECT_TRUE(buffer->GetFormat()->IsFloat32()); EXPECT_EQ(Format::Layout::kStd430, buffer->GetFormat()->GetLayout()); EXPECT_EQ(5U, buffer->ElementCount()); EXPECT_EQ(5U, buffer->ValueCount()); @@ -348,7 +347,7 @@ TEST_F(AmberScriptParserTest, BufferSeriesFloat) { auto* buffer = buffers[0].get(); EXPECT_EQ("my_buffer", buffer->GetName()); - EXPECT_TRUE(buffer->GetFormat()->IsFloat()); + EXPECT_TRUE(buffer->GetFormat()->IsFloat32()); EXPECT_EQ(Format::Layout::kStd430, buffer->GetFormat()->GetLayout()); EXPECT_EQ(5U, buffer->ElementCount()); EXPECT_EQ(5U, buffer->ValueCount()); @@ -564,21 +563,15 @@ TEST_F(AmberScriptParserTest, BufferFormat) { EXPECT_EQ("my_buf", buffer->GetName()); auto fmt = buffer->GetFormat(); + EXPECT_EQ(FormatType::kR32G32B32A32_SINT, fmt->GetFormatType()); auto& segs = fmt->GetSegments(); ASSERT_EQ(4U, segs.size()); - EXPECT_EQ(FormatComponentType::kR, segs[0].GetComponent()->type); - EXPECT_EQ(FormatMode::kSInt, segs[0].GetComponent()->mode); - EXPECT_EQ(32U, segs[0].GetComponent()->num_bits); - EXPECT_EQ(FormatComponentType::kG, segs[1].GetComponent()->type); - EXPECT_EQ(FormatMode::kSInt, segs[1].GetComponent()->mode); - EXPECT_EQ(32U, segs[1].GetComponent()->num_bits); - EXPECT_EQ(FormatComponentType::kB, segs[2].GetComponent()->type); - EXPECT_EQ(FormatMode::kSInt, segs[2].GetComponent()->mode); - EXPECT_EQ(32U, segs[2].GetComponent()->num_bits); - EXPECT_EQ(FormatComponentType::kA, segs[3].GetComponent()->type); - EXPECT_EQ(FormatMode::kSInt, segs[3].GetComponent()->mode); - EXPECT_EQ(32U, segs[3].GetComponent()->num_bits); + for (size_t i = 0; i < 4; ++i) { + EXPECT_EQ(segs[i].GetNumBits(), 32); + EXPECT_EQ(segs[i].GetFormatMode(), FormatMode::kSInt); + EXPECT_EQ(segs[i].GetName(), static_cast<FormatComponentType>(i)); + } } struct BufferParseError { @@ -697,12 +690,11 @@ TEST_P(AmberScriptParserBufferDataTypeTest, BufferTypes) { auto* buffer = buffers[0].get(); auto fmt = buffer->GetFormat(); - EXPECT_EQ(test_data.row_count, fmt->RowCount()); - EXPECT_EQ(test_data.column_count, fmt->ColumnCount()); + EXPECT_EQ(test_data.row_count, fmt->GetType()->RowCount()); + EXPECT_EQ(test_data.column_count, fmt->GetType()->ColumnCount()); - auto comp = fmt->GetSegments()[0].GetComponent(); - EXPECT_EQ(test_data.type, comp->mode); - EXPECT_EQ(test_data.num_bits, comp->num_bits); + EXPECT_EQ(test_data.type, fmt->GetSegments()[0].GetFormatMode()); + EXPECT_EQ(test_data.num_bits, fmt->GetSegments()[0].GetNumBits()); } INSTANTIATE_TEST_SUITE_P( AmberScriptParserTestsDataType, @@ -715,16 +707,16 @@ INSTANTIATE_TEST_SUITE_P( BufferData{"uint16", FormatMode::kUInt, 16, 1, 1}, BufferData{"uint32", FormatMode::kUInt, 32, 1, 1}, BufferData{"uint64", FormatMode::kUInt, 64, 1, 1}, - BufferData{"float", FormatMode::kSFloat, 32, 1, 1}, - BufferData{"double", FormatMode::kSFloat, 64, 1, 1}, BufferData{"vec2<int8>", FormatMode::kSInt, 8, 2, 1}, - BufferData{"vec3<float>", FormatMode::kSFloat, 32, 3, 1}, BufferData{"vec4<uint32>", FormatMode::kUInt, 32, 4, 1}, BufferData{"mat2x4<int32>", FormatMode::kSInt, 32, 4, 2}, - BufferData{"mat3x3<float>", FormatMode::kSFloat, 32, 3, 3}, BufferData{"mat4x2<uint16>", FormatMode::kUInt, 16, 2, 4}, - BufferData{"B8G8R8_UNORM", FormatMode::kUNorm, 8, 3, - 1})); // NOLINT(whitespace/parens) + BufferData{"B8G8R8_UNORM", FormatMode::kUNorm, 8, 3, 1}, + BufferData{"float", FormatMode::kSFloat, 32, 1, 1}, + BufferData{"double", FormatMode::kSFloat, 64, 1, 1}, + BufferData{"vec3<float>", FormatMode::kSFloat, 32, 3, 1}, + BufferData{"mat3x3<float>", FormatMode::kSFloat, 32, 3, + 3})); // NOLINT(whitespace/parens) struct NameData { const char* name; diff --git a/src/buffer.cc b/src/buffer.cc index 5a42508..c8b8f96 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -60,33 +60,35 @@ double Sub(const uint8_t* buf1, const uint8_t* buf2) { *reinterpret_cast<const T*>(buf2)); } -double CalculateDiff(const Format::Component* comp, +double CalculateDiff(const Format::Segment* seg, const uint8_t* buf1, const uint8_t* buf2) { - if (comp->IsInt8()) + FormatMode mode = seg->GetFormatMode(); + uint32_t num_bits = seg->GetNumBits(); + if (type::Type::IsInt8(mode, num_bits)) return Sub<int8_t>(buf1, buf2); - if (comp->IsInt16()) + if (type::Type::IsInt16(mode, num_bits)) return Sub<int16_t>(buf1, buf2); - if (comp->IsInt32()) + if (type::Type::IsInt32(mode, num_bits)) return Sub<int32_t>(buf1, buf2); - if (comp->IsInt64()) + if (type::Type::IsInt64(mode, num_bits)) return Sub<int64_t>(buf1, buf2); - if (comp->IsUint8()) + if (type::Type::IsUint8(mode, num_bits)) return Sub<uint8_t>(buf1, buf2); - if (comp->IsUint16()) + if (type::Type::IsUint16(mode, num_bits)) return Sub<uint16_t>(buf1, buf2); - if (comp->IsUint32()) + if (type::Type::IsUint32(mode, num_bits)) return Sub<uint32_t>(buf1, buf2); - if (comp->IsUint64()) + if (type::Type::IsUint64(mode, num_bits)) return Sub<uint64_t>(buf1, buf2); // TOOD(dsinclair): Handle float16 ... - if (comp->IsFloat16()) { + if (type::Type::IsFloat16(mode, num_bits)) { assert(false && "Float16 suppport not implemented"); return 0.0; } - if (comp->IsFloat()) + if (type::Type::IsFloat32(mode, num_bits)) return Sub<float>(buf1, buf2); - if (comp->IsDouble()) + if (type::Type::IsFloat64(mode, num_bits)) return Sub<double>(buf1, buf2); assert(false && "NOTREACHED"); @@ -159,12 +161,16 @@ std::vector<double> Buffer::CalculateDiffs(const Buffer* buffer) const { const auto& segments = format_->GetSegments(); for (size_t i = 0; i < ElementCount(); ++i) { for (const auto& seg : segments) { - if (!seg.IsPadding()) - diffs.push_back( - CalculateDiff(seg.GetComponent(), buf_1_ptr, buf_2_ptr)); + if (seg.IsPadding()) { + buf_1_ptr += seg.PaddingBytes(); + buf_2_ptr += seg.PaddingBytes(); + continue; + } + + diffs.push_back(CalculateDiff(&seg, buf_1_ptr, buf_2_ptr)); - buf_1_ptr += seg.GetComponent()->SizeInBytes(); - buf_2_ptr += seg.GetComponent()->SizeInBytes(); + buf_1_ptr += seg.SizeInBytes(); + buf_2_ptr += seg.SizeInBytes(); } } @@ -210,7 +216,7 @@ Result Buffer::RecalculateMaxSizeInBytes(const std::vector<Value>& data, ((offset / format_->SizeInBytes()) * format_->InputNeededPerElement()) + static_cast<uint32_t>(data.size()); uint32_t element_count = value_count; - if (format_->GetPackSize() == 0) { + if (!format_->IsPacked()) { // This divides by the needed input values, not the values per element. // The assumption being the values coming in are read from the input, // where components are specified. The needed values maybe less then the @@ -229,6 +235,7 @@ Result Buffer::SetDataWithOffset(const std::vector<Value>& data, uint32_t value_count = ((offset / format_->SizeInBytes()) * format_->InputNeededPerElement()) + static_cast<uint32_t>(data.size()); + // The buffer should only be resized to become bigger. This means that if a // command was run to set the buffer size we'll honour that size until a // request happens to make the buffer bigger. @@ -254,82 +261,68 @@ Result Buffer::SetDataWithOffset(const std::vector<Value>& data, uint8_t* ptr = bytes_.data() + offset; const auto& segments = format_->GetSegments(); for (uint32_t i = 0; i < data.size();) { - const auto pack_size = format_->GetPackSize(); - if (pack_size) { - if (pack_size == 8) { - *(ValuesAs<uint8_t>(ptr)) = data[i].AsUint8(); - ptr += sizeof(uint8_t); - } else if (pack_size == 16) { - *(ValuesAs<uint16_t>(ptr)) = data[i].AsUint16(); - ptr += sizeof(uint16_t); - } else if (pack_size == 32) { - *(ValuesAs<uint32_t>(ptr)) = data[i].AsUint32(); - ptr += sizeof(uint32_t); - } - ++i; - continue; - } - for (const auto& seg : segments) { - Value v; - if (!seg.IsPadding()) { - v = data[i]; - ++i; + if (seg.IsPadding()) { + ptr += seg.PaddingBytes(); + continue; } - ptr += WriteValueFromComponent(v, seg.GetComponent(), ptr); + Value v = data[i++]; + ptr += WriteValueFromComponent(v, seg.GetFormatMode(), seg.GetNumBits(), + ptr); } } return {}; } uint32_t Buffer::WriteValueFromComponent(const Value& value, - const Format::Component* comp, + FormatMode mode, + uint32_t num_bits, uint8_t* ptr) { - if (comp->IsInt8()) { + if (type::Type::IsInt8(mode, num_bits)) { *(ValuesAs<int8_t>(ptr)) = value.AsInt8(); return sizeof(int8_t); } - if (comp->IsInt16()) { + if (type::Type::IsInt16(mode, num_bits)) { *(ValuesAs<int16_t>(ptr)) = value.AsInt16(); return sizeof(int16_t); } - if (comp->IsInt32()) { + if (type::Type::IsInt32(mode, num_bits)) { *(ValuesAs<int32_t>(ptr)) = value.AsInt32(); return sizeof(int32_t); } - if (comp->IsInt64()) { + if (type::Type::IsInt64(mode, num_bits)) { *(ValuesAs<int64_t>(ptr)) = value.AsInt64(); return sizeof(int64_t); } - if (comp->IsUint8()) { + if (type::Type::IsUint8(mode, num_bits)) { *(ValuesAs<uint8_t>(ptr)) = value.AsUint8(); return sizeof(uint8_t); } - if (comp->IsUint16()) { + if (type::Type::IsUint16(mode, num_bits)) { *(ValuesAs<uint16_t>(ptr)) = value.AsUint16(); return sizeof(uint16_t); } - if (comp->IsUint32()) { + if (type::Type::IsUint32(mode, num_bits)) { *(ValuesAs<uint32_t>(ptr)) = value.AsUint32(); return sizeof(uint32_t); } - if (comp->IsUint64()) { + if (type::Type::IsUint64(mode, num_bits)) { *(ValuesAs<uint64_t>(ptr)) = value.AsUint64(); return sizeof(uint64_t); } - if (comp->IsFloat()) { + if (type::Type::IsFloat16(mode, num_bits)) { + *(ValuesAs<uint16_t>(ptr)) = FloatToHexFloat16(value.AsFloat()); + return sizeof(uint16_t); + } + if (type::Type::IsFloat32(mode, num_bits)) { *(ValuesAs<float>(ptr)) = value.AsFloat(); return sizeof(float); } - if (comp->IsDouble()) { + if (type::Type::IsFloat64(mode, num_bits)) { *(ValuesAs<double>(ptr)) = value.AsDouble(); return sizeof(double); } - if (comp->IsFloat16()) { - *(ValuesAs<uint16_t>(ptr)) = FloatToHexFloat16(value.AsFloat()); - return sizeof(uint16_t); - } // The float 10 and float 11 sizes are only used in PACKED formats. assert(false && "Not reached"); diff --git a/src/buffer.h b/src/buffer.h index 813b6aa..7eec699 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -108,7 +108,7 @@ class Buffer { element_count_ = 0; return; } - if (format_->GetPackSize() > 0) { + if (format_->IsPacked()) { element_count_ = count; } else { // This divides by the needed input values, not the values per element. @@ -123,9 +123,9 @@ class Buffer { if (!format_) return 0; // Packed formats are single values. - if (format_->GetPackSize() > 0) + if (format_->IsPacked()) return element_count_; - return element_count_ * format_->ValuesPerElement(); + return element_count_ * format_->InputNeededPerElement(); } /// Returns the number of bytes needed for the data in the buffer. @@ -198,7 +198,8 @@ class Buffer { private: uint32_t WriteValueFromComponent(const Value& value, - const Format::Component* comp, + FormatMode mode, + uint32_t num_bits, uint8_t* ptr); // Calculates the difference between the value stored in this buffer and diff --git a/src/buffer_test.cc b/src/buffer_test.cc index 5c52c0f..a869f7e 100644 --- a/src/buffer_test.cc +++ b/src/buffer_test.cc @@ -17,7 +17,7 @@ #include <utility> #include "gtest/gtest.h" -#include "src/format_parser.h" +#include "src/type_parser.h" namespace amber { @@ -31,11 +31,12 @@ TEST_F(BufferTest, EmptyByDefault) { } TEST_F(BufferTest, Size) { - FormatParser fp; - auto fmt = fp.Parse("R16_SINT"); + TypeParser parser; + auto type = parser.Parse("R16_SINT"); + Format fmt(type.get()); Buffer b(BufferType::kColor); - b.SetFormat(fmt.get()); + b.SetFormat(&fmt); b.SetElementCount(10); EXPECT_EQ(10, b.ElementCount()); EXPECT_EQ(10, b.ValueCount()); @@ -46,11 +47,12 @@ TEST_F(BufferTest, SizeFromData) { std::vector<Value> values; values.resize(5); - FormatParser fp; - auto fmt = fp.Parse("R32_SFLOAT"); + TypeParser parser; + auto type = parser.Parse("R32_SFLOAT"); + Format fmt(type.get()); Buffer b(BufferType::kColor); - b.SetFormat(fmt.get()); + b.SetFormat(&fmt); b.SetData(std::move(values)); EXPECT_EQ(5, b.ElementCount()); @@ -62,11 +64,12 @@ TEST_F(BufferTest, SizeFromDataDoesNotOverrideSize) { std::vector<Value> values; values.resize(5); - FormatParser fp; - auto fmt = fp.Parse("R32_SFLOAT"); + TypeParser parser; + auto type = parser.Parse("R32_SFLOAT"); + Format fmt(type.get()); Buffer b(BufferType::kColor); - b.SetFormat(fmt.get()); + b.SetFormat(&fmt); b.SetElementCount(20); b.SetData(std::move(values)); @@ -76,12 +79,13 @@ TEST_F(BufferTest, SizeFromDataDoesNotOverrideSize) { } TEST_F(BufferTest, SizeMatrixStd430) { - FormatParser fp; - auto fmt = fp.Parse("R16G16_SINT"); - fmt->SetColumnCount(3); + TypeParser parser; + auto type = parser.Parse("R16G16_SINT"); + type->SetColumnCount(3); + Format fmt(type.get()); Buffer b(BufferType::kColor); - b.SetFormat(fmt.get()); + b.SetFormat(&fmt); b.SetElementCount(10); EXPECT_EQ(10, b.ElementCount()); @@ -90,31 +94,33 @@ TEST_F(BufferTest, SizeMatrixStd430) { } TEST_F(BufferTest, SizeMatrixStd140) { - FormatParser fp; - auto fmt = fp.Parse("R16G16_SINT"); - fmt->SetColumnCount(3); - fmt->SetLayout(Format::Layout::kStd140); + TypeParser parser; + auto type = parser.Parse("R16G16_SINT"); + type->SetColumnCount(3); + Format fmt(type.get()); + fmt.SetLayout(Format::Layout::kStd140); Buffer b(BufferType::kColor); - b.SetFormat(fmt.get()); + b.SetFormat(&fmt); b.SetElementCount(10); EXPECT_EQ(10, b.ElementCount()); - EXPECT_EQ(120, b.ValueCount()); + EXPECT_EQ(10 * 2 * 3, b.ValueCount()); EXPECT_EQ(120 * sizeof(int16_t), b.GetSizeInBytes()); } TEST_F(BufferTest, SizeMatrixPaddedStd430) { - FormatParser fp; - auto fmt = fp.Parse("R32G32B32_SINT"); - fmt->SetColumnCount(3); + TypeParser parser; + auto type = parser.Parse("R32G32B32_SINT"); + type->SetColumnCount(3); + Format fmt(type.get()); Buffer b(BufferType::kColor); - b.SetFormat(fmt.get()); + b.SetFormat(&fmt); b.SetValueCount(9); EXPECT_EQ(1U, b.ElementCount()); - EXPECT_EQ(12U, b.ValueCount()); + EXPECT_EQ(9U, b.ValueCount()); EXPECT_EQ(12U * sizeof(int32_t), b.GetSizeInBytes()); } diff --git a/src/format.cc b/src/format.cc index 66e5e76..221bcff 100644 --- a/src/format.cc +++ b/src/format.cc @@ -14,47 +14,75 @@ #include "src/format.h" +#include <algorithm> +#include <utility> + #include "src/make_unique.h" +#include "src/type_parser.h" namespace amber { +namespace { -Format::Format() = default; +std::string FormatModeToName(FormatMode mode) { + switch (mode) { + case FormatMode::kUNorm: + return "UNORM"; + case FormatMode::kUInt: + return "UINT"; + case FormatMode::kUScaled: + return "USCALED"; + case FormatMode::kSInt: + return "SINT"; + case FormatMode::kSNorm: + return "SNORM"; + case FormatMode::kSScaled: + return "SSCALED"; + case FormatMode::kSRGB: + return "SRGB"; + case FormatMode::kSFloat: + return "SFLOAT"; + case FormatMode::kUFloat: + return "UFLOAT"; + } + + return ""; +} + +uint32_t CalculatePad(uint32_t val) { + if ((val % 16) == 0) + return 0; + return 16 - (val % 16); +} + +} // namespace + +Format::Format(type::Type* type) : type_(type) { + auto name = GenerateName(); + if (name == "") + format_type_ = FormatType::kUnknown; + else + format_type_ = TypeParser::NameToFormatType(name); + RebuildSegments(); +} Format::~Format() = default; uint32_t Format::SizeInBytes() const { uint32_t size = 0; - for (const auto& seg : segments_) - size += static_cast<uint32_t>(seg.GetComponent()->SizeInBytes()); + for (const auto& seg : segments_) { + if (seg.IsPadding()) { + size += seg.PaddingBytes(); + continue; + } + size += static_cast<uint32_t>(seg.SizeInBytes()); + } return size; } -bool Format::AreAllComponents(FormatMode mode, uint32_t bits) const { - for (const auto& comp : components_) { - if (comp->mode != mode || comp->num_bits != bits) - return false; - } - return true; -} - bool Format::Equal(const Format* b) const { - if (type_ != b->type_ || layout_ != b->layout_ || - pack_size_in_bytes_ != b->pack_size_in_bytes_ || - column_count_ != b->column_count_) { - return false; - } - if (components_.size() != b->components_.size()) - return false; - - for (uint32_t i = 0; i < components_.size(); ++i) { - if (components_[i]->type != b->components_[i]->type || - components_[i]->mode != b->components_[i]->mode || - components_[i]->num_bits != b->components_[i]->num_bits) { - return false; - } - } - return true; + return format_type_ == b->format_type_ && layout_ == b->layout_ && + type_->Equal(b->type_); } uint32_t Format::InputNeededPerElement() const { @@ -68,18 +96,6 @@ uint32_t Format::InputNeededPerElement() const { return count; } -void Format::AddComponent(FormatComponentType type, - FormatMode mode, - uint8_t bits) { - components_.push_back(MakeUnique<Component>(type, mode, bits)); - RebuildSegments(); -} - -void Format::SetColumnCount(uint32_t c) { - column_count_ = c; - RebuildSegments(); -} - void Format::SetLayout(Layout layout) { layout_ = layout; RebuildSegments(); @@ -87,55 +103,308 @@ void Format::SetLayout(Layout layout) { void Format::RebuildSegments() { segments_.clear(); + AddSegmentsForType(type_); +} + +void Format::AddPaddedSegment(uint32_t size) { + // If the last item was already padding we just extend by the |size| bytes + if (!segments_.empty() && segments_.back().IsPadding()) { + segments_[segments_.size() - 1] = + Segment{size + segments_.back().SizeInBytes()}; + } else { + segments_.push_back(Segment{size}); + } +} + +void Format::AddPaddedSegmentPackable(uint32_t size) { + AddPaddedSegment(size); + segments_.back().SetPackable(true); +} + +bool Format::AddSegment(const Segment& seg) { + if (!segments_.empty()) { + auto last = segments_.back(); + + if (last.IsPackable() && last.IsPadding() && + last.SizeInBytes() >= seg.SizeInBytes()) { + segments_.back() = seg; + auto pad = last.SizeInBytes() - seg.SizeInBytes(); + if (pad > 0) + AddPaddedSegmentPackable(pad); + + return false; + } + } + segments_.push_back(seg); + return true; +} + +bool Format::NeedsPadding(type::Type* t) const { + if (layout_ == Layout::kStd140 && (t->IsMatrix() || t->IsArray())) + return true; + if (t->IsVec3() || (t->IsMatrix() && t->RowCount() == 3)) + return true; + return false; +} + +uint32_t Format::CalcVecBaseAlignmentInBytes(type::Number* n) const { + // vec3 rounds up to a Vec4, so 4 * N + if (n->IsVec3()) + return 4 * n->SizeInBytes(); + + // vec2 and vec4 are 2 * N and 4 * N respectively + return n->RowCount() * n->SizeInBytes(); +} + +uint32_t Format::CalcArrayBaseAlignmentInBytes(type::Type* t) const { + uint32_t align = 0; + if (t->IsStruct()) { + align = CalcStructBaseAlignmentInBytes(t->AsStruct()); + } else if (t->IsMatrix()) { + align = CalcMatrixBaseAlignmentInBytes(t->AsNumber()); + } else if (t->IsVec()) { + align = CalcVecBaseAlignmentInBytes(t->AsNumber()); + } else if (t->IsList()) { + align = CalcListBaseAlignmentInBytes(t->AsList()); + } else if (t->IsNumber()) { + align = t->SizeInBytes(); + } + + // In std140 array elements round up to multiple of vec4. + if (layout_ == Layout::kStd140) + align += CalculatePad(align); + + return align; +} + +uint32_t Format::CalcStructBaseAlignmentInBytes(type::Struct* s) const { + uint32_t base_alignment = 0; + for (const auto& member : s->Members()) { + base_alignment = + std::max(base_alignment, CalcTypeBaseAlignmentInBytes(member.type)); + } + + return base_alignment; +} + +uint32_t Format::CalcMatrixBaseAlignmentInBytes(type::Number* m) const { + // TODO(dsinclair): Deal with row major when needed. Currently this assumes + // the matrix is column major. + + uint32_t align = 0; + if (m->RowCount() == 3) + align = 4 * m->SizeInBytes(); + else + align = m->RowCount() * m->SizeInBytes(); - for (size_t i = 0; i < column_count_; ++i) { - for (size_t k = 0; k < components_.size(); ++k) { - segments_.push_back(Segment{components_[k].get()}); + // STD140 rounds up to 16 byte alignment + if (layout_ == Layout::kStd140) + align += CalculatePad(align); + + return align; +} + +uint32_t Format::CalcListBaseAlignmentInBytes(type::List* l) const { + return l->SizeInBytes(); +} + +uint32_t Format::CalcTypeBaseAlignmentInBytes(type::Type* t) const { + if (t->IsArray()) + return CalcArrayBaseAlignmentInBytes(t); + if (t->IsVec()) + return CalcVecBaseAlignmentInBytes(t->AsNumber()); + if (t->IsMatrix()) + return CalcMatrixBaseAlignmentInBytes(t->AsNumber()); + if (t->IsNumber()) + return t->SizeInBytes(); + if (t->IsList()) + return CalcListBaseAlignmentInBytes(t->AsList()); + if (t->IsStruct()) { + // Pad struct to 16 bytes in STD140 + uint32_t base = CalcStructBaseAlignmentInBytes(t->AsStruct()); + if (layout_ == Layout::kStd140) + base += CalculatePad(base); + return base; + } + + assert(false && "Not reached"); + return 0; +} + +uint32_t Format::AddSegmentsForType(type::Type* type) { + if (type->IsList() && type->AsList()->IsPacked()) { + auto l = type->AsList(); + if (AddSegment(Segment(FormatComponentType::kR, FormatMode::kUInt, + l->PackSizeInBits()))) { + return l->SizeInBytes(); + } + return 0; + } + + // Remove packable from previous packing for types which can't pack back. + if (type->IsStruct() || type->IsVec() || type->IsMatrix() || + type->IsArray()) { + if (!segments_.empty() && segments_.back().IsPadding()) + segments_.back().SetPackable(false); + } + + // TODO(dsinclair): How to handle matrix stride .... Stride comes from parent + // member .... + + if (type->IsStruct()) { + auto s = type->AsStruct(); + auto base_alignment_in_bytes = CalcStructBaseAlignmentInBytes(s); + + uint32_t cur_offset = 0; + for (const auto& member : s->Members()) { + if (member.HasOffset()) { + assert(static_cast<uint32_t>(member.offset_in_bytes) >= cur_offset); + + AddPaddedSegment(static_cast<uint32_t>(member.offset_in_bytes) - + cur_offset); + cur_offset = static_cast<uint32_t>(member.offset_in_bytes); + } + + uint32_t seg_size = 0; + if (member.type->IsSizedArray()) { + for (size_t i = 0; i < member.type->ArraySize(); ++i) { + auto ary_seg_size = AddSegmentsForType(member.type); + // Don't allow array members to pack together + if (!segments_.empty() && segments_.back().IsPadding()) + segments_.back().SetPackable(false); + + if (member.HasArrayStride()) { + uint32_t array_stride = + static_cast<uint32_t>(member.array_stride_in_bytes); + assert(ary_seg_size <= array_stride && + "Array element larger than stride"); + + seg_size += array_stride; + } else { + seg_size += ary_seg_size; + } + } + } else { + seg_size = AddSegmentsForType(member.type); + } + + if (seg_size > 0 && seg_size < base_alignment_in_bytes) { + AddPaddedSegmentPackable(base_alignment_in_bytes - seg_size); + seg_size += base_alignment_in_bytes - seg_size; + } + + cur_offset += seg_size; + } + if (s->HasStride()) { + assert(cur_offset <= s->StrideInBytes() && + "Struct has more members then fit within stride"); + AddPaddedSegment(s->StrideInBytes() - cur_offset); + cur_offset = s->StrideInBytes(); + } else if (layout_ == Layout::kStd140) { + // Round struct up to 16 byte alignment in STD140. + auto pad = CalculatePad(cur_offset); + if (pad > 0) { + AddPaddedSegment(pad); + cur_offset += pad; + } + } + return cur_offset; + } + + // List members are only numbers and must not be vecs or matrices. + if (type->IsList()) { + uint32_t size = 0; + auto l = type->AsList(); + for (uint32_t i = 0; i < type->ColumnCount(); ++i) { + for (const auto& m : l->Members()) { + if (AddSegment(Segment{m.name, m.mode, m.num_bits})) + size += m.SizeInBytes(); + } + + if (NeedsPadding(type)) { + auto& seg = l->Members().back(); + for (size_t k = 0; k < (4 - type->RowCount()); ++k) { + AddPaddedSegment(seg.SizeInBytes()); + size += seg.SizeInBytes(); + } + } + } + return size; + } + + auto n = type->AsNumber(); + uint32_t size = 0; + for (uint32_t i = 0; i < type->ColumnCount(); ++i) { + for (uint32_t k = 0; k < type->RowCount(); ++k) { + if (AddSegment(Segment{static_cast<FormatComponentType>(i), + n->GetFormatMode(), n->NumBits()})) { + size += type->SizeInBytes(); + } } // In std140 a matrix (column count > 1) has each row stored like an array // which rounds up to a vec4. // // In std140 and std430 a vector of size 3N will round up to a vector of 4N. - if ((layout_ == Layout::kStd140 && column_count_ > 1) || RowCount() == 3) { - for (size_t k = 0; k < (4 - RowCount()); ++k) { - // TODO(dsinclair): This component will be wrong if all the components - // aren't the same size. This will be the case when we have struct - // support .... - segments_.push_back(Segment{components_[0].get()}); - segments_.back().SetIsPadding(); + if (NeedsPadding(type)) { + for (size_t k = 0; k < (4 - type->RowCount()); ++k) { + AddPaddedSegmentPackable(type->SizeInBytes()); + size += type->SizeInBytes(); } } + + // Make sure matrix rows don't accidentally pack together. + if (type->IsMatrix() && segments_.back().IsPadding()) + segments_.back().SetPackable(false); } + return size; } std::string Format::GenerateName() const { - std::string name = ""; - std::string parts = "ARGB"; - for (const auto& comp : components_) { - name += parts[static_cast<uint8_t>(comp->type)] + - std::to_string(comp->num_bits); + if (type_->IsMatrix()) + return ""; + + static const char NAME_PARTS[] = "RGBAXDS"; + if (type_->IsList()) { + std::vector<std::pair<std::string, std::string>> parts; + const auto& members = type_->AsList()->Members(); + for (size_t i = 0; i < members.size(); ++i) { + const auto& member = members[i]; + std::string name(1, NAME_PARTS[static_cast<uint8_t>(member.name)]); + name += std::to_string(member.num_bits); + + std::string type = FormatModeToName(member.mode); + parts.push_back({name, type}); + } + + std::string name = ""; + for (size_t i = 0; i < parts.size(); ++i) { + name += parts[i].first; + + if (i + 1 < parts.size() && parts[i].second != parts[i + 1].second) + name += "_" + parts[i].second + "_"; + + // Handle the X8_D24 underscore. + if (parts[i].first[0] == 'X') + name += "_"; + } + name += "_" + parts.back().second; + if (type_->AsList()->IsPacked()) + name += "_PACK" + std::to_string(type_->AsList()->PackSizeInBits()); + + return name; } - name += "_"; - switch (components_[0]->mode) { - case FormatMode::kUNorm: - case FormatMode::kUFloat: - case FormatMode::kUScaled: - case FormatMode::kSNorm: - case FormatMode::kSScaled: - case FormatMode::kSRGB: - return ""; - case FormatMode::kUInt: - name += "UINT"; - break; - case FormatMode::kSInt: - name += "SINT"; - break; - case FormatMode::kSFloat: - name += "SFLOAT"; - break; + + if (type_->IsNumber()) { + std::string name = ""; + for (uint32_t i = 0; i < type_->RowCount(); ++i) + name += NAME_PARTS[i] + std::to_string(type_->SizeInBytes() * 8); + + name += "_" + FormatModeToName(type_->AsNumber()->GetFormatMode()); + return name; } - return name; + + return ""; } } // namespace amber diff --git a/src/format.h b/src/format.h index c101790..e6e68ba 100644 --- a/src/format.h +++ b/src/format.h @@ -17,12 +17,12 @@ #include <cassert> #include <cstdint> -#include <memory> #include <string> #include <vector> #include "src/format_data.h" #include "src/make_unique.h" +#include "src/type.h" namespace amber { @@ -41,116 +41,70 @@ class Format { public: enum Layout { kStd140 = 0, kStd430 }; - /// Describes an individual component of a format. - struct Component { - Component(FormatComponentType t, FormatMode m, uint8_t bits) - : type(t), mode(m), num_bits(bits) {} - - FormatComponentType type; - 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 { - return (mode == FormatMode::kSInt || mode == FormatMode::kSNorm || - mode == FormatMode::kSScaled || mode == FormatMode::kSRGB) && - num_bits == 8; - } - /// Is this component represented by a 16 bit signed integer. (This includes - /// int and norm values) - bool IsInt16() const { - return (mode == FormatMode::kSInt || mode == FormatMode::kSNorm) && - num_bits == 16; - } - /// Is this component represented by a 32 bit signed integer. - bool IsInt32() const { return mode == FormatMode::kSInt && num_bits == 32; } - /// Is this component represented by a 64 bit signed integer. - bool IsInt64() const { return mode == FormatMode::kSInt && num_bits == 64; } - /// Is this component represented by an 8 bit unsigned integer. (This - /// includes uint, unorm and uscaled values). - bool IsUint8() const { - return (mode == FormatMode::kUInt || mode == FormatMode::kUNorm || - mode == FormatMode::kUScaled) && - num_bits == 8; - } - /// Is this component represented by a 16 bit unsigned integer. - bool IsUint16() const { - return mode == FormatMode::kUInt && num_bits == 16; - } - /// Is this component represented by a 32 bit unsigned integer. - bool IsUint32() const { - return mode == FormatMode::kUInt && num_bits == 32; - } - /// Is this component represented by a 64 bit unsigned integer. - bool IsUint64() const { - return mode == FormatMode::kUInt && num_bits == 64; - } - /// Is this component represented by a 16 bit floating point value. - bool IsFloat16() const { - return mode == FormatMode::kSFloat && num_bits == 16; - } - /// Is this component represented by a 32 bit floating point value - bool IsFloat() const { - return mode == FormatMode::kSFloat && num_bits == 32; - } - /// Is this component represented by a 64 bit floating point value - bool IsDouble() const { - return mode == FormatMode::kSFloat && num_bits == 64; - } - }; - class Segment { public: - explicit Segment(Component* component) : component_(component) {} - Segment(const Segment&) = default; - ~Segment() = default; - - Segment& operator=(const Segment&) = default; + explicit Segment(uint32_t num_bytes) + : is_padding_(true), num_bits_(num_bytes * 8) {} + Segment(FormatComponentType name, FormatMode mode, uint32_t num_bits) + : name_(name), mode_(mode), num_bits_(num_bits) {} - void SetIsPadding() { is_padding_ = true; } bool IsPadding() const { return is_padding_; } + uint32_t PaddingBytes() const { return num_bits_ / 8; } - Component* GetComponent() const { return component_; } + FormatComponentType GetName() const { return name_; } + FormatMode GetFormatMode() const { return mode_; } + uint32_t GetNumBits() const { return num_bits_; } + + uint32_t SizeInBytes() const { return num_bits_ / 8; } + + // The packable flag can be set on padding segments. This means, the next + // byte, if it's the same type as this packing, can be inserted before + // this packing segment as long as it fits within the pack size, removing + // that much pack space. + bool IsPackable() const { return is_packable_; } + void SetPackable(bool packable) { is_packable_ = packable; } private: - Component* component_; bool is_padding_ = false; + bool is_packable_ = false; + FormatComponentType name_ = FormatComponentType::kR; + FormatMode mode_ = FormatMode::kSInt; + uint32_t num_bits_ = 0; }; /// Creates a format of unknown type. - Format(); + explicit Format(type::Type* type); ~Format(); + static bool IsNormalized(FormatMode mode) { + return mode == FormatMode::kUNorm || mode == FormatMode::kSNorm || + mode == FormatMode::kSRGB; + } + /// Returns true if |b| describes the same format as this object. bool Equal(const Format* b) const; /// Sets the type of the format. For image types this maps closely to the /// list of Vulkan formats. For data types, this maybe Unknown if the data /// type can not be represented by the image format (e.g. matrix types) - void SetFormatType(FormatType type) { type_ = type; } - FormatType GetFormatType() const { return type_; } + void SetFormatType(FormatType type) { format_type_ = type; } + FormatType GetFormatType() const { return format_type_; } void SetLayout(Layout layout); Layout GetLayout() const { return layout_; } - /// Set the number of bytes this format is packed into, if provided. - void SetPackSize(uint8_t size_in_bytes) { - pack_size_in_bytes_ = size_in_bytes; - } - /// Retrieves the number of bytes this format is packed into. - uint8_t GetPackSize() const { return pack_size_in_bytes_; } + type::Type* GetType() const { return type_; } - void AddComponent(FormatComponentType type, FormatMode mode, uint8_t bits); + /// Returns a pointer to the only type in this format. Only valid if + /// there is only an int or float type, nullptr otherwise. + type::Type* GetOnlyType() const { + if (type_->IsNumber()) + return type_; + return nullptr; + } - /// Returns a pointer to the only component in this format. Only valid if - /// there is only a single component, asserts otherwise. - Component* GetOnlyComponent() const { - assert(components_.size() == 1); - return components_[0].get(); + bool IsPacked() const { + return type_->IsList() && type_->AsList()->IsPacked(); } /// The segment is the individual pieces of the components including padding. @@ -159,19 +113,28 @@ class Format { /// Returns the number of bytes this format requires. uint32_t SizeInBytes() const; - bool IsFormatKnown() const { return type_ != FormatType::kUnknown; } + bool IsFormatKnown() const { return format_type_ != FormatType::kUnknown; } bool HasStencilComponent() const { - return type_ == FormatType::kD24_UNORM_S8_UINT || - type_ == FormatType::kD16_UNORM_S8_UINT || - type_ == FormatType::kD32_SFLOAT_S8_UINT || - type_ == FormatType::kS8_UINT; + return format_type_ == FormatType::kD24_UNORM_S8_UINT || + format_type_ == FormatType::kD16_UNORM_S8_UINT || + format_type_ == FormatType::kD32_SFLOAT_S8_UINT || + format_type_ == FormatType::kS8_UINT; } /// Returns true if the format components are normalized. bool IsNormalized() const { - FormatMode mode = components_.back()->mode; - return mode == FormatMode::kUNorm || mode == FormatMode::kSNorm || - mode == FormatMode::kSRGB; + if (type_->IsNumber() && IsNormalized(type_->AsNumber()->GetFormatMode())) + return true; + + if (type_->IsList()) { + for (auto& member : type_->AsList()->Members()) { + if (!IsNormalized(member.mode)) { + return false; + } + } + return true; + } + return false; } /// Returns the number of input values required for an item of this format. @@ -179,52 +142,93 @@ class Format { /// account. uint32_t InputNeededPerElement() const; - /// Returns the number of values for a given row, including padding. - uint32_t ValuesPerElement() const { - return static_cast<uint32_t>(segments_.size()); - } - - /// Returns the number of values for a given row, excluding padding. - uint32_t RowCount() const { - return static_cast<uint32_t>(components_.size()); - } - uint32_t ColumnCount() const { return column_count_; } - void SetColumnCount(uint32_t c); - /// Returns true if all components of this format are an 8 bit signed int. - bool IsInt8() const { return AreAllComponents(FormatMode::kSInt, 8); } + bool IsInt8() const { + return type_->IsNumber() && + type::Type::IsInt8(type_->AsNumber()->GetFormatMode(), + type_->AsNumber()->NumBits()); + } /// Returns true if all components of this format are a 16 bit signed int. - bool IsInt16() const { return AreAllComponents(FormatMode::kSInt, 16); } + bool IsInt16() const { + return type_->IsNumber() && + type::Type::IsInt16(type_->AsNumber()->GetFormatMode(), + type_->AsNumber()->NumBits()); + } /// Returns true if all components of this format are a 32 bit signed int. - bool IsInt32() const { return AreAllComponents(FormatMode::kSInt, 32); } + bool IsInt32() const { + return type_->IsNumber() && + type::Type::IsInt32(type_->AsNumber()->GetFormatMode(), + type_->AsNumber()->NumBits()); + } /// Returns true if all components of this format are a 64 bit signed int. - bool IsInt64() const { return AreAllComponents(FormatMode::kSInt, 64); } + bool IsInt64() const { + return type_->IsNumber() && + type::Type::IsInt64(type_->AsNumber()->GetFormatMode(), + type_->AsNumber()->NumBits()); + } /// Returns true if all components of this format are a 8 bit unsigned int. - bool IsUint8() const { return AreAllComponents(FormatMode::kUInt, 8); } + bool IsUint8() const { + return type_->IsNumber() && + type::Type::IsUint8(type_->AsNumber()->GetFormatMode(), + type_->AsNumber()->NumBits()); + } /// Returns true if all components of this format are a 16 bit unsigned int. - bool IsUint16() const { return AreAllComponents(FormatMode::kUInt, 16); } + bool IsUint16() const { + return type_->IsNumber() && + type::Type::IsUint16(type_->AsNumber()->GetFormatMode(), + type_->AsNumber()->NumBits()); + } /// Returns true if all components of this format are a 32 bit unsigned int. - bool IsUint32() const { return AreAllComponents(FormatMode::kUInt, 32); } + bool IsUint32() const { + return type_->IsNumber() && + type::Type::IsUint32(type_->AsNumber()->GetFormatMode(), + type_->AsNumber()->NumBits()); + } /// Returns true if all components of this format are a 64 bit unsigned int. - bool IsUint64() const { return AreAllComponents(FormatMode::kUInt, 64); } + bool IsUint64() const { + return type_->IsNumber() && + type::Type::IsUint64(type_->AsNumber()->GetFormatMode(), + type_->AsNumber()->NumBits()); + } /// Returns true if all components of this format are a 32 bit float. - bool IsFloat() const { return AreAllComponents(FormatMode::kSFloat, 32); } + bool IsFloat32() const { + return type_->IsNumber() && + type::Type::IsFloat32(type_->AsNumber()->GetFormatMode(), + type_->AsNumber()->NumBits()); + } /// Returns true if all components of this format are a 64 bit float. - bool IsDouble() const { return AreAllComponents(FormatMode::kSFloat, 64); } + bool IsFloat64() const { + return type_->IsNumber() && + type::Type::IsFloat64(type_->AsNumber()->GetFormatMode(), + type_->AsNumber()->NumBits()); + } - /// Generates the image format name for this format if possible. Returns - /// the name if generated or "" otherwise. - std::string GenerateName() const; + std::string GenerateNameForTesting() const { return GenerateName(); } private: - bool AreAllComponents(FormatMode mode, uint32_t bits) const; void RebuildSegments(); + uint32_t AddSegmentsForType(type::Type* type); + bool NeedsPadding(type::Type* t) const; + // Returns true if a segment was added, false if we packed the requested + // segment into previously allocated space. + bool AddSegment(const Segment& seg); + void AddPaddedSegment(uint32_t size); + void AddPaddedSegmentPackable(uint32_t size); + uint32_t CalcTypeBaseAlignmentInBytes(type::Type* s) const; + uint32_t CalcStructBaseAlignmentInBytes(type::Struct* s) const; + uint32_t CalcVecBaseAlignmentInBytes(type::Number* n) const; + uint32_t CalcArrayBaseAlignmentInBytes(type::Type* t) const; + uint32_t CalcMatrixBaseAlignmentInBytes(type::Number* m) const; + uint32_t CalcListBaseAlignmentInBytes(type::List* l) const; + + /// Generates the image format name for this format if possible. Returns + /// the name if generated or "" otherwise. + std::string GenerateName() const; - FormatType type_ = FormatType::kUnknown; + FormatType format_type_ = FormatType::kUnknown; Layout layout_ = Layout::kStd430; - uint8_t pack_size_in_bytes_ = 0; - uint32_t column_count_ = 1; - std::vector<std::unique_ptr<Component>> components_; + type::Type* type_; + std::vector<FormatComponentType> type_names_; std::vector<Segment> segments_; }; diff --git a/src/format_data.h b/src/format_data.h index 98237bf..ff860c8 100644 --- a/src/format_data.h +++ b/src/format_data.h @@ -16,10 +16,10 @@ #define SRC_FORMAT_DATA_H_ enum class FormatComponentType { - kA = 0, - kR, + kR = 0, kG, kB, + kA, kX, kD, kS, diff --git a/src/format_parser.h b/src/format_parser.h deleted file mode 100644 index 7257bf1..0000000 --- a/src/format_parser.h +++ /dev/null @@ -1,54 +0,0 @@ -// 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 -// -// http://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. - -#ifndef SRC_FORMAT_PARSER_H_ -#define SRC_FORMAT_PARSER_H_ - -#include <memory> -#include <string> -#include <vector> - -#include "src/format.h" - -namespace amber { - -/// Parses a Vulkan image string into a format object. -class FormatParser { - public: - static FormatType NameToType(const std::string& data); - - FormatParser(); - ~FormatParser(); - - std::unique_ptr<Format> Parse(const std::string& fmt); - - private: - std::unique_ptr<Format> ParseGlslFormat(const std::string& fmt); - void ProcessChunk(Format*, const std::string&); - void AddPiece(FormatComponentType type, uint8_t bits); - void FlushPieces(Format* fmt, FormatMode mode); - - struct Pieces { - Pieces(FormatComponentType t, uint8_t bits) : type(t), num_bits(bits) {} - - FormatComponentType type; - uint8_t num_bits; - }; - - std::vector<Pieces> pieces_; -}; - -} // namespace amber - -#endif // SRC_FORMAT_PARSER_H_ diff --git a/src/format_test.cc b/src/format_test.cc index b148888..341faac 100644 --- a/src/format_test.cc +++ b/src/format_test.cc @@ -15,48 +15,49 @@ #include "src/format.h" #include "gtest/gtest.h" -#include "src/format_parser.h" #include "src/make_unique.h" +#include "src/type_parser.h" namespace amber { using FormatTest = testing::Test; -TEST_F(FormatTest, SizeInBytesVector) { - FormatParser fp; - auto fmt = fp.Parse("R32G32B32_SFLOAT"); - ASSERT_TRUE(fmt != nullptr); - - EXPECT_EQ(3U, fmt->InputNeededPerElement()); - EXPECT_EQ(16U, fmt->SizeInBytes()); +TEST_F(FormatTest, DefaultToStd430) { + auto f32 = type::Number::Float(32); + Format fmt(f32.get()); + EXPECT_EQ(Format::Layout::kStd430, fmt.GetLayout()); } -TEST_F(FormatTest, SizeInBytesMatrix) { - FormatParser fp; - auto fmt = fp.Parse("R32G32B32_SFLOAT"); - ASSERT_TRUE(fmt != nullptr); - fmt->SetColumnCount(3); +TEST_F(FormatTest, SizeInBytesVector_Std430) { + TypeParser parser; + auto type = parser.Parse("R32G32B32_SFLOAT"); + ASSERT_TRUE(type != nullptr); - EXPECT_EQ(9U, fmt->InputNeededPerElement()); - EXPECT_EQ(48U, fmt->SizeInBytes()); + Format fmt(type.get()); + EXPECT_EQ(3U, fmt.InputNeededPerElement()); + EXPECT_EQ(16U, fmt.SizeInBytes()); } -TEST_F(FormatTest, SizeInBytesMatrixStd140) { - FormatParser fp; - auto fmt = fp.Parse("R32G32_SFLOAT"); - ASSERT_TRUE(fmt != nullptr); - fmt->SetColumnCount(2); - fmt->SetLayout(Format::Layout::kStd140); +TEST_F(FormatTest, SizeInBytesMatrix_Std430) { + TypeParser parser; + auto type = parser.Parse("R32G32B32_SFLOAT"); + ASSERT_TRUE(type != nullptr); + type->SetColumnCount(3); - EXPECT_EQ(32U, fmt->SizeInBytes()); + Format fmt(type.get()); + EXPECT_EQ(9U, fmt.InputNeededPerElement()); + EXPECT_EQ(48U, fmt.SizeInBytes()); } -TEST_F(FormatTest, RowCount) { - FormatParser fp; - auto fmt = fp.Parse("R32G32B32_SFLOAT"); - ASSERT_TRUE(fmt != nullptr); +TEST_F(FormatTest, SizeInBytesMatrix_Std140) { + TypeParser parser; + auto type = parser.Parse("R32G32_SFLOAT"); + ASSERT_TRUE(type != nullptr); + type->SetColumnCount(2); - EXPECT_EQ(3U, fmt->RowCount()); + Format fmt(type.get()); + fmt.SetLayout(Format::Format::Layout::kStd140); + EXPECT_EQ(32U, fmt.SizeInBytes()); } struct StdData { @@ -70,15 +71,17 @@ using FormatStdTest = testing::TestWithParam<StdData>; TEST_P(FormatStdTest, Test) { auto test_data = GetParam(); - FormatParser fp; - auto fmt = fp.Parse(test_data.fmt); - ASSERT_TRUE(fmt != nullptr) << test_data.name; + TypeParser parser; + auto type = parser.Parse(test_data.fmt); + ASSERT_TRUE(type != nullptr) << test_data.name; + + type->SetColumnCount(test_data.column_count); - fmt->SetColumnCount(test_data.column_count); + Format fmt(type.get()); if (test_data.is_std140) - fmt->SetLayout(Format::Layout::kStd140); + fmt.SetLayout(Format::Format::Layout::kStd140); - EXPECT_EQ(test_data.size_in_bytes, fmt->SizeInBytes()) << test_data.name; + EXPECT_EQ(test_data.size_in_bytes, fmt.SizeInBytes()) << test_data.name; } INSTANTIATE_TEST_SUITE_P( @@ -107,4 +110,1074 @@ INSTANTIATE_TEST_SUITE_P( StdData{"float-std430", "R32_SFLOAT", 1, false, 4U})); // NOLINT(whitespace/parens) +struct Name { + const char* name; +}; +using FormatNameTest = testing::TestWithParam<Name>; + +TEST_P(FormatNameTest, Test) { + auto test_data = GetParam(); + + TypeParser parser; + auto type = parser.Parse(test_data.name); + ASSERT_TRUE(type != nullptr) << test_data.name; + + Format fmt(type.get()); + EXPECT_EQ(test_data.name, fmt.GenerateNameForTesting()); +} +INSTANTIATE_TEST_SUITE_P( + FormatNameGenerateTest, + FormatNameTest, + testing::Values(Name{"A1R5G5B5_UNORM_PACK16"}, + Name{"A2B10G10R10_SINT_PACK32"}, + Name{"A2B10G10R10_SNORM_PACK32"}, + Name{"A2B10G10R10_SSCALED_PACK32"}, + Name{"A2B10G10R10_UINT_PACK32"}, + Name{"A2B10G10R10_UNORM_PACK32"}, + Name{"A2B10G10R10_USCALED_PACK32"}, + Name{"A2R10G10B10_SINT_PACK32"}, + Name{"A2R10G10B10_SNORM_PACK32"}, + Name{"A2R10G10B10_SSCALED_PACK32"}, + Name{"A2R10G10B10_UINT_PACK32"}, + Name{"A2R10G10B10_UNORM_PACK32"}, + Name{"A2R10G10B10_USCALED_PACK32"}, + Name{"A8B8G8R8_SINT_PACK32"}, + Name{"A8B8G8R8_SNORM_PACK32"}, + Name{"A8B8G8R8_SRGB_PACK32"}, + Name{"A8B8G8R8_SSCALED_PACK32"}, + Name{"A8B8G8R8_UINT_PACK32"}, + Name{"A8B8G8R8_UNORM_PACK32"}, + Name{"A8B8G8R8_USCALED_PACK32"}, + Name{"B10G11R11_UFLOAT_PACK32"}, + Name{"B4G4R4A4_UNORM_PACK16"}, + Name{"B5G5R5A1_UNORM_PACK16"}, + Name{"B5G6R5_UNORM_PACK16"}, + Name{"B8G8R8A8_SINT"}, + Name{"B8G8R8A8_SNORM"}, + Name{"B8G8R8A8_SRGB"}, + Name{"B8G8R8A8_SSCALED"}, + Name{"B8G8R8A8_UINT"}, + Name{"B8G8R8A8_UNORM"}, + Name{"B8G8R8A8_USCALED"}, + Name{"B8G8R8_SINT"}, + Name{"B8G8R8_SNORM"}, + Name{"B8G8R8_SRGB"}, + Name{"B8G8R8_SSCALED"}, + Name{"B8G8R8_UINT"}, + Name{"B8G8R8_UNORM"}, + Name{"B8G8R8_USCALED"}, + Name{"D16_UNORM"}, + Name{"D16_UNORM_S8_UINT"}, + Name{"D24_UNORM_S8_UINT"}, + Name{"D32_SFLOAT"}, + Name{"D32_SFLOAT_S8_UINT"}, + Name{"R16G16B16A16_SFLOAT"}, + Name{"R16G16B16A16_SINT"}, + Name{"R16G16B16A16_SNORM"}, + Name{"R16G16B16A16_SSCALED"}, + Name{"R16G16B16A16_UINT"}, + Name{"R16G16B16A16_UNORM"}, + Name{"R16G16B16A16_USCALED"}, + Name{"R16G16B16_SFLOAT"}, + Name{"R16G16B16_SINT"}, + Name{"R16G16B16_SNORM"}, + Name{"R16G16B16_SSCALED"}, + Name{"R16G16B16_UINT"}, + Name{"R16G16B16_UNORM"}, + Name{"R16G16B16_USCALED"}, + Name{"R16G16_SFLOAT"}, + Name{"R16G16_SINT"}, + Name{"R16G16_SNORM"}, + Name{"R16G16_SSCALED"}, + Name{"R16G16_UINT"}, + Name{"R16G16_UNORM"}, + Name{"R16G16_USCALED"}, + Name{"R16_SFLOAT"}, + Name{"R16_SINT"}, + Name{"R16_SNORM"}, + Name{"R16_SSCALED"}, + Name{"R16_UINT"}, + Name{"R16_UNORM"}, + Name{"R16_USCALED"}, + Name{"R32G32B32A32_SFLOAT"}, + Name{"R32G32B32A32_SINT"}, + Name{"R32G32B32A32_UINT"}, + Name{"R32G32B32_SFLOAT"}, + Name{"R32G32B32_SINT"}, + Name{"R32G32B32_UINT"}, + Name{"R32G32_SFLOAT"}, + Name{"R32G32_SINT"}, + Name{"R32G32_UINT"}, + Name{"R32_SFLOAT"}, + Name{"R32_SINT"}, + Name{"R32_UINT"}, + Name{"R4G4B4A4_UNORM_PACK16"}, + Name{"R4G4_UNORM_PACK8"}, + Name{"R5G5B5A1_UNORM_PACK16"}, + Name{"R5G6B5_UNORM_PACK16"}, + Name{"R64G64B64A64_SFLOAT"}, + Name{"R64G64B64A64_SINT"}, + Name{"R64G64B64A64_UINT"}, + Name{"R64G64B64_SFLOAT"}, + Name{"R64G64B64_SINT"}, + Name{"R64G64B64_UINT"}, + Name{"R64G64_SFLOAT"}, + Name{"R64G64_SINT"}, + Name{"R64G64_UINT"}, + Name{"R64_SFLOAT"}, + Name{"R64_SINT"}, + Name{"R64_UINT"}, + Name{"R8G8B8A8_SINT"}, + Name{"R8G8B8A8_SNORM"}, + Name{"R8G8B8A8_SRGB"}, + Name{"R8G8B8A8_SSCALED"}, + Name{"R8G8B8A8_UINT"}, + Name{"R8G8B8A8_UNORM"}, + Name{"R8G8B8A8_USCALED"}, + Name{"R8G8B8_SINT"}, + Name{"R8G8B8_SNORM"}, + Name{"R8G8B8_SRGB"}, + Name{"R8G8B8_SSCALED"}, + Name{"R8G8B8_UINT"}, + Name{"R8G8B8_UNORM"}, + Name{"R8G8B8_USCALED"}, + Name{"R8G8_SINT"}, + Name{"R8G8_SNORM"}, + Name{"R8G8_SRGB"}, + Name{"R8G8_SSCALED"}, + Name{"R8G8_UINT"}, + Name{"R8G8_UNORM"}, + Name{"R8G8_USCALED"}, + Name{"R8_SINT"}, + Name{"R8_SNORM"}, + Name{"R8_SRGB"}, + Name{"R8_SSCALED"}, + Name{"R8_UINT"}, + Name{"R8_UNORM"}, + Name{"R8_USCALED"}, + Name{"S8_UINT"}, + Name{"X8_D24_UNORM_PACK32"})); // NOLINT(whitespace/parens) + +TEST_F(FormatTest, SegmentPackedList_Std430) { + TypeParser parser; + auto type = parser.Parse("A8B8G8R8_SINT_PACK32"); + + Format fmt(type.get()); + EXPECT_EQ(4, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(1U, segs.size()); + // Always packs into a unsigned ... + EXPECT_EQ(FormatMode::kUInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); +} + +TEST_F(FormatTest, SegmentListR32G32_Std140) { + TypeParser parser; + auto type = parser.Parse("R32G32_UINT"); + + Format fmt(type.get()); + fmt.SetLayout(Format::Layout::kStd140); + EXPECT_EQ(8, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(2U, segs.size()); + EXPECT_EQ(FormatMode::kUInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_EQ(FormatMode::kUInt, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); +} + +TEST_F(FormatTest, SegmentListR32G32B32_Std140) { + TypeParser parser; + auto type = parser.Parse("R32G32B32_UINT"); + + Format fmt(type.get()); + fmt.SetLayout(Format::Layout::kStd140); + EXPECT_EQ(16, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(4U, segs.size()); + EXPECT_EQ(FormatMode::kUInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_EQ(FormatMode::kUInt, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + EXPECT_EQ(FormatMode::kUInt, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + EXPECT_TRUE(segs[3].IsPadding()); + EXPECT_EQ(4, segs[3].SizeInBytes()); +} + +TEST_F(FormatTest, SegmentListR32G32B32_Std430) { + TypeParser parser; + auto type = parser.Parse("R32G32B32_UINT"); + + Format fmt(type.get()); + fmt.SetLayout(Format::Format::Layout::kStd430); + EXPECT_EQ(16, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(4U, segs.size()); + EXPECT_EQ(FormatMode::kUInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_EQ(FormatMode::kUInt, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + EXPECT_EQ(FormatMode::kUInt, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + EXPECT_TRUE(segs[3].IsPadding()); + EXPECT_EQ(4, segs[3].SizeInBytes()); +} + +TEST_F(FormatTest, SegmentMat2x2_Std140) { + TypeParser parser; + auto type = parser.Parse("R32G32_SFLOAT"); + type->SetColumnCount(2); + + Format fmt(type.get()); + fmt.SetLayout(Format::Format::Layout::kStd140); + EXPECT_EQ(32, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(6U, segs.size()); + EXPECT_EQ(FormatMode::kSFloat, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + EXPECT_TRUE(segs[2].IsPadding()); + EXPECT_EQ(8, segs[2].SizeInBytes()); + + EXPECT_EQ(FormatMode::kSFloat, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[4].GetFormatMode()); + EXPECT_EQ(4, segs[4].SizeInBytes()); + EXPECT_TRUE(segs[5].IsPadding()); + EXPECT_EQ(8, segs[5].SizeInBytes()); +} + +TEST_F(FormatTest, SegmentMat2x2_Std430) { + TypeParser parser; + auto type = parser.Parse("R32G32_SFLOAT"); + type->SetColumnCount(2); + + Format fmt(type.get()); + fmt.SetLayout(Format::Layout::kStd430); + EXPECT_EQ(16, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(4U, segs.size()); + EXPECT_EQ(FormatMode::kSFloat, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + + EXPECT_EQ(FormatMode::kSFloat, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); +} + +TEST_F(FormatTest, SegmentMat2x3_Std430) { + TypeParser parser; + auto type = parser.Parse("R32G32B32_SFLOAT"); + type->SetColumnCount(2); + + Format fmt(type.get()); + fmt.SetLayout(Format::Layout::kStd430); + EXPECT_EQ(32, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(8U, segs.size()); + EXPECT_EQ(FormatMode::kSFloat, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + EXPECT_TRUE(segs[3].IsPadding()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + + EXPECT_EQ(FormatMode::kSFloat, segs[4].GetFormatMode()); + EXPECT_EQ(4, segs[4].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[5].GetFormatMode()); + EXPECT_EQ(4, segs[5].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[6].GetFormatMode()); + EXPECT_EQ(4, segs[6].SizeInBytes()); + EXPECT_TRUE(segs[7].IsPadding()); + EXPECT_EQ(4, segs[7].SizeInBytes()); +} + +TEST_F(FormatTest, SegmentRuntimeArray_Std140) { + TypeParser parser; + auto type = parser.Parse("R32_SFLOAT"); + type->SetIsRuntimeArray(); + + Format fmt(type.get()); + fmt.SetLayout(Format::Format::Layout::kStd140); + EXPECT_EQ(16, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(2U, segs.size()); + EXPECT_EQ(FormatMode::kSFloat, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_TRUE(segs[1].IsPadding()); + EXPECT_EQ(12, segs[1].SizeInBytes()); +} + +TEST_F(FormatTest, SegmentRuntimeArray_Std430) { + TypeParser parser; + auto type = parser.Parse("R32_SFLOAT"); + type->SetIsRuntimeArray(); + + Format fmt(type.get()); + fmt.SetLayout(Format::Layout::kStd430); + EXPECT_EQ(4, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(1U, segs.size()); + EXPECT_EQ(FormatMode::kSFloat, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); +} + +// struct { +// float x; +// int32 y; +// } +TEST_F(FormatTest, SegmentStruct_Std140) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto u32 = type::Number::Uint(32); + s->AddMember(f32.get()); + s->AddMember(u32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd140); + EXPECT_EQ(16, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(3, segs.size()); + EXPECT_EQ(FormatMode::kSFloat, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_EQ(FormatMode::kUInt, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + EXPECT_TRUE(segs[2].IsPadding()); + EXPECT_EQ(8, segs[2].SizeInBytes()); +} +TEST_F(FormatTest, SegmentStruct_Std430) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto u32 = type::Number::Uint(32); + s->AddMember(f32.get()); + s->AddMember(u32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd430); + EXPECT_EQ(8, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(2U, segs.size()); + EXPECT_EQ(FormatMode::kSFloat, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_EQ(FormatMode::kUInt, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); +} + +// struct STRIDE 20 { +// float x; +// int32 y; +// } +// Note, the STRIDE is the stride over the entire structure. +TEST_F(FormatTest, SegmentStructWithStride_Std140) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto u32 = type::Number::Uint(32); + s->AddMember(f32.get()); + s->AddMember(u32.get()); + s->SetStrideInBytes(20); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd140); + EXPECT_EQ(20, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(3U, segs.size()); + EXPECT_EQ(FormatMode::kSFloat, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_EQ(FormatMode::kUInt, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + EXPECT_TRUE(segs[2].IsPadding()); + EXPECT_EQ((20 - sizeof(float) - sizeof(uint32_t)), segs[2].SizeInBytes()); +} +TEST_F(FormatTest, SegmentStructWithStride_Std430) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto u32 = type::Number::Uint(32); + s->AddMember(f32.get()); + s->AddMember(u32.get()); + s->SetStrideInBytes(20); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd430); + EXPECT_EQ(20, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(3U, segs.size()); + EXPECT_EQ(FormatMode::kSFloat, segs[0].GetFormatMode()); + EXPECT_EQ(32U, segs[0].GetNumBits()); + EXPECT_EQ(FormatMode::kUInt, segs[1].GetFormatMode()); + EXPECT_EQ(32U, segs[1].GetNumBits()); + EXPECT_TRUE(segs[2].IsPadding()); + EXPECT_EQ((20 - sizeof(float) - sizeof(uint32_t)) * 8, segs[2].GetNumBits()); +} + +// struct { +// float x OFFSET 4; +// int32 y; +// } +TEST_F(FormatTest, SegmentStructWithMemberOffset_Std140) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto u32 = type::Number::Uint(32); + + auto m = s->AddMember(f32.get()); + m->offset_in_bytes = 4; + + s->AddMember(u32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd140); + EXPECT_EQ(16, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(4U, segs.size()); + EXPECT_TRUE(segs[0].IsPadding()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + EXPECT_EQ(FormatMode::kUInt, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + EXPECT_TRUE(segs[3].IsPadding()); + EXPECT_EQ(4, segs[3].SizeInBytes()); +} +TEST_F(FormatTest, SegmentStructWithMemberOffset_Std430) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto u32 = type::Number::Uint(32); + + auto m = s->AddMember(f32.get()); + m->offset_in_bytes = 4; + + s->AddMember(u32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd430); + EXPECT_EQ(12, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(3U, segs.size()); + EXPECT_TRUE(segs[0].IsPadding()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + EXPECT_EQ(FormatMode::kUInt, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); +} + +// struct { +// struct { +// int32 a; +// float b; +// } x; +// float y; +// } +TEST_F(FormatTest, SegmentStructWithStruct_Std140) { + auto x = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto i32 = type::Number::Int(32); + x->AddMember(i32.get()); + x->AddMember(f32.get()); + + auto s = MakeUnique<type::Struct>(); + s->AddMember(x.get()); + s->AddMember(f32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd140); + EXPECT_EQ(32, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(5U, segs.size()); + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + EXPECT_TRUE(segs[2].IsPadding()); + EXPECT_EQ(8, segs[2].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + EXPECT_TRUE(segs[4].IsPadding()); + EXPECT_EQ(12, segs[4].SizeInBytes()); +} +TEST_F(FormatTest, SegmentStructWithStruct_Std430) { + auto x = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto i32 = type::Number::Int(32); + x->AddMember(i32.get()); + x->AddMember(f32.get()); + + auto s = MakeUnique<type::Struct>(); + s->AddMember(x.get()); + s->AddMember(f32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd430); + EXPECT_EQ(12, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(3U, segs.size()); + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); +} + +// struct { +// int32 w; +// vec2<float> x; +// float y; +// } +TEST_F(FormatTest, SegmentStructWithVec2_Std140) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto i32 = type::Number::Int(32); + auto vec2 = type::Number::Float(32); + vec2->SetRowCount(2); + + s->AddMember(i32.get()); + s->AddMember(vec2.get()); + s->AddMember(f32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd140); + EXPECT_EQ(32, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(6U, segs.size()); + /* w */ + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[1].IsPadding()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + /* vec2 */ + EXPECT_EQ(FormatMode::kSFloat, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + /* y */ + EXPECT_EQ(FormatMode::kSFloat, segs[4].GetFormatMode()); + EXPECT_EQ(4, segs[4].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[5].IsPadding()); + EXPECT_EQ(12, segs[5].SizeInBytes()); +} +TEST_F(FormatTest, SegmentStructWithVec2_Std430) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto i32 = type::Number::Int(32); + auto vec2 = type::Number::Float(32); + vec2->SetRowCount(2); + + s->AddMember(i32.get()); + s->AddMember(vec2.get()); + s->AddMember(f32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd430); + EXPECT_EQ(24, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(6U, segs.size()); + /* w */ + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[1].IsPadding()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + /* vec2 */ + EXPECT_EQ(FormatMode::kSFloat, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + /* y */ + EXPECT_EQ(FormatMode::kSFloat, segs[4].GetFormatMode()); + EXPECT_EQ(4, segs[4].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[5].IsPadding()); + EXPECT_EQ(4, segs[5].SizeInBytes()); +} + +// struct { +// int32 w; +// vec3<float> x; +// float y; +// } +TEST_F(FormatTest, SegmentStructWithFloatPackedToVec_Std140) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto i32 = type::Number::Int(32); + auto vec3 = type::Number::Float(32); + vec3->SetRowCount(3); + + s->AddMember(i32.get()); + s->AddMember(vec3.get()); + s->AddMember(f32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd140); + EXPECT_EQ(32, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(6U, segs.size()); + /* w */ + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[1].IsPadding()); + EXPECT_EQ(12, segs[1].SizeInBytes()); + /* vec2 */ + EXPECT_EQ(FormatMode::kSFloat, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[4].GetFormatMode()); + EXPECT_EQ(4, segs[4].SizeInBytes()); + /* y */ + EXPECT_EQ(FormatMode::kSFloat, segs[5].GetFormatMode()); + EXPECT_EQ(4, segs[5].SizeInBytes()); +} +TEST_F(FormatTest, SegmentStructWithFloatPackedToVec_Std430) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto i32 = type::Number::Int(32); + auto vec3 = type::Number::Float(32); + vec3->SetRowCount(3); + + s->AddMember(i32.get()); + s->AddMember(vec3.get()); + s->AddMember(f32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd430); + EXPECT_EQ(32, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(6U, segs.size()); + /* w */ + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[1].IsPadding()); + EXPECT_EQ(12, segs[1].SizeInBytes()); + /* vec2 */ + EXPECT_EQ(FormatMode::kSFloat, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[4].GetFormatMode()); + EXPECT_EQ(4, segs[4].SizeInBytes()); + /* y */ + EXPECT_EQ(FormatMode::kSFloat, segs[5].GetFormatMode()); + EXPECT_EQ(4, segs[5].SizeInBytes()); +} + +// struct { +// int32 w; +// vec3<float> x; +// vec2<float> y; +// } +TEST_F(FormatTest, SegmentStructVec3Vec2_Std140) { + auto s = MakeUnique<type::Struct>(); + auto i32 = type::Number::Int(32); + auto vec3 = type::Number::Float(32); + vec3->SetRowCount(3); + auto vec2 = type::Number::Float(32); + vec2->SetRowCount(2); + + s->AddMember(i32.get()); + s->AddMember(vec3.get()); + s->AddMember(vec2.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd140); + EXPECT_EQ(48, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(9U, segs.size()); + /* w */ + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[1].IsPadding()); + EXPECT_EQ(12, segs[1].SizeInBytes()); + /* vec3 */ + EXPECT_EQ(FormatMode::kSFloat, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[4].GetFormatMode()); + EXPECT_EQ(4, segs[4].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[5].IsPadding()); + EXPECT_EQ(4, segs[5].SizeInBytes()); + /* vec2 */ + EXPECT_EQ(FormatMode::kSFloat, segs[6].GetFormatMode()); + EXPECT_EQ(4, segs[6].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[7].GetFormatMode()); + EXPECT_EQ(4, segs[7].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[8].IsPadding()); + EXPECT_EQ(8, segs[8].SizeInBytes()); +} +TEST_F(FormatTest, SegmentStructVec3Vec2_Std430) { + auto s = MakeUnique<type::Struct>(); + auto i32 = type::Number::Int(32); + auto vec3 = type::Number::Float(32); + vec3->SetRowCount(3); + auto vec2 = type::Number::Float(32); + vec2->SetRowCount(2); + + s->AddMember(i32.get()); + s->AddMember(vec3.get()); + s->AddMember(vec2.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd430); + EXPECT_EQ(48, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(9U, segs.size()); + /* w */ + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[1].IsPadding()); + EXPECT_EQ(12, segs[1].SizeInBytes()); + /* vec3 */ + EXPECT_EQ(FormatMode::kSFloat, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[4].GetFormatMode()); + EXPECT_EQ(4, segs[4].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[5].IsPadding()); + EXPECT_EQ(4, segs[5].SizeInBytes()); + /* vec2 */ + EXPECT_EQ(FormatMode::kSFloat, segs[6].GetFormatMode()); + EXPECT_EQ(4, segs[6].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[7].GetFormatMode()); + EXPECT_EQ(4, segs[7].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[8].IsPadding()); + EXPECT_EQ(8, segs[8].SizeInBytes()); +} + +// struct { +// int32 w; +// mat2x2<float> x; +// float y; +// } +TEST_F(FormatTest, SegmentStructMat2x2_Std140) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto i32 = type::Number::Int(32); + auto mat2x2 = type::Number::Float(32); + mat2x2->SetRowCount(2); + mat2x2->SetColumnCount(2); + + s->AddMember(i32.get()); + s->AddMember(mat2x2.get()); + s->AddMember(f32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd140); + EXPECT_EQ(64, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(10U, segs.size()); + /* w */ + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[1].IsPadding()); + EXPECT_EQ(12, segs[1].SizeInBytes()); + /* column 1 */ + EXPECT_EQ(FormatMode::kSFloat, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + EXPECT_TRUE(segs[4].IsPadding()); + EXPECT_EQ(8, segs[4].SizeInBytes()); + /* column 2 */ + EXPECT_EQ(FormatMode::kSFloat, segs[5].GetFormatMode()); + EXPECT_EQ(4, segs[5].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[6].GetFormatMode()); + EXPECT_EQ(4, segs[6].SizeInBytes()); + EXPECT_TRUE(segs[7].IsPadding()); + EXPECT_EQ(8, segs[7].SizeInBytes()); + /* y */ + EXPECT_EQ(FormatMode::kSFloat, segs[8].GetFormatMode()); + EXPECT_EQ(4, segs[8].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[9].IsPadding()); + EXPECT_EQ(12, segs[9].SizeInBytes()); +} +TEST_F(FormatTest, SegmentStructMat2x2_Std430) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto i32 = type::Number::Int(32); + auto mat2x2 = type::Number::Float(32); + mat2x2->SetRowCount(2); + mat2x2->SetColumnCount(2); + + s->AddMember(i32.get()); + s->AddMember(mat2x2.get()); + s->AddMember(f32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd430); + EXPECT_EQ(32, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(8U, segs.size()); + /* w */ + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[1].IsPadding()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + /* column 1 */ + EXPECT_EQ(FormatMode::kSFloat, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + /* column 2 */ + EXPECT_EQ(FormatMode::kSFloat, segs[4].GetFormatMode()); + EXPECT_EQ(4, segs[4].SizeInBytes()); + EXPECT_EQ(FormatMode::kSFloat, segs[5].GetFormatMode()); + EXPECT_EQ(4, segs[5].SizeInBytes()); + /* y */ + EXPECT_EQ(FormatMode::kSFloat, segs[6].GetFormatMode()); + EXPECT_EQ(4, segs[6].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[7].IsPadding()); + EXPECT_EQ(4, segs[7].SizeInBytes()); +} + +// struct { +// int32 w; +// struct { +// int32 a; +// int32 b; +// float c; +// } x; +// float y; +// } +TEST_F(FormatTest, SegmentStructWithStructNoPack_Std140) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto i32 = type::Number::Int(32); + auto x = MakeUnique<type::Struct>(); + x->AddMember(i32.get()); + x->AddMember(i32.get()); + x->AddMember(f32.get()); + + s->AddMember(i32.get()); + s->AddMember(x.get()); + s->AddMember(f32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd140); + EXPECT_EQ(48, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(8U, segs.size()); + /* w */ + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[1].IsPadding()); + EXPECT_EQ(12, segs[1].SizeInBytes()); + /* a */ + EXPECT_EQ(FormatMode::kSInt, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + /* b */ + EXPECT_EQ(FormatMode::kSInt, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + /* c */ + EXPECT_EQ(FormatMode::kSFloat, segs[4].GetFormatMode()); + EXPECT_EQ(4, segs[4].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[5].IsPadding()); + EXPECT_EQ(4, segs[5].SizeInBytes()); + /* y */ + EXPECT_EQ(FormatMode::kSFloat, segs[6].GetFormatMode()); + EXPECT_EQ(4, segs[6].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[7].IsPadding()); + EXPECT_EQ(12, segs[7].SizeInBytes()); +} +TEST_F(FormatTest, SegmentStructWithStructNoPack_Std430) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto i32 = type::Number::Int(32); + auto x = MakeUnique<type::Struct>(); + x->AddMember(i32.get()); + x->AddMember(i32.get()); + x->AddMember(f32.get()); + + s->AddMember(i32.get()); + s->AddMember(x.get()); + s->AddMember(f32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd430); + EXPECT_EQ(20, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(5U, segs.size()); + /* w */ + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + /* a */ + EXPECT_EQ(FormatMode::kSInt, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + /* b */ + EXPECT_EQ(FormatMode::kSInt, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + /* c */ + EXPECT_EQ(FormatMode::kSFloat, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + /* y */ + EXPECT_EQ(FormatMode::kSFloat, segs[4].GetFormatMode()); + EXPECT_EQ(4, segs[4].SizeInBytes()); +} + +// struct { +// int32 w; +// struct { +// int32 a; +// int32 b; +// float c[3]; +// } x; +// float y; +// } +TEST_F(FormatTest, SegmentStructWithStructArray_Std140) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto i32 = type::Number::Int(32); + auto f32_ary = type::Number::Float(32); + f32_ary->SetIsSizedArray(3); + + auto x = MakeUnique<type::Struct>(); + x->AddMember(i32.get()); + x->AddMember(i32.get()); + x->AddMember(f32_ary.get()); + + s->AddMember(i32.get()); + s->AddMember(x.get()); + s->AddMember(f32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd140); + EXPECT_EQ(96, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(13U, segs.size()); + /* w */ + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[1].IsPadding()); + EXPECT_EQ(12, segs[1].SizeInBytes()); + /* a */ + EXPECT_EQ(FormatMode::kSInt, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + /* b */ + EXPECT_EQ(FormatMode::kSInt, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[4].IsPadding()); + EXPECT_EQ(8, segs[4].SizeInBytes()); + /* c[0] */ + EXPECT_EQ(FormatMode::kSFloat, segs[5].GetFormatMode()); + EXPECT_EQ(4, segs[5].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[6].IsPadding()); + EXPECT_EQ(12, segs[6].SizeInBytes()); + /* c[1] */ + EXPECT_EQ(FormatMode::kSFloat, segs[7].GetFormatMode()); + EXPECT_EQ(4, segs[7].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[8].IsPadding()); + EXPECT_EQ(12, segs[8].SizeInBytes()); + /* c[2] */ + EXPECT_EQ(FormatMode::kSFloat, segs[9].GetFormatMode()); + EXPECT_EQ(4, segs[9].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[10].IsPadding()); + EXPECT_EQ(12, segs[10].SizeInBytes()); + /* y */ + EXPECT_EQ(FormatMode::kSFloat, segs[11].GetFormatMode()); + EXPECT_EQ(4, segs[11].SizeInBytes()); + /* pad */ + EXPECT_TRUE(segs[12].IsPadding()); + EXPECT_EQ(12, segs[12].SizeInBytes()); +} +TEST_F(FormatTest, SegmentStructWithStructArray_Std430) { + auto s = MakeUnique<type::Struct>(); + auto f32 = type::Number::Float(32); + auto i32 = type::Number::Int(32); + auto f32_ary = type::Number::Float(32); + f32_ary->SetIsSizedArray(3); + auto x = MakeUnique<type::Struct>(); + x->AddMember(i32.get()); + x->AddMember(i32.get()); + x->AddMember(f32_ary.get()); + + s->AddMember(i32.get()); + s->AddMember(x.get()); + s->AddMember(f32.get()); + + Format fmt(s.get()); + fmt.SetLayout(Format::Layout::kStd430); + EXPECT_EQ(28, fmt.SizeInBytes()); + + const auto& segs = fmt.GetSegments(); + ASSERT_EQ(7U, segs.size()); + /* w */ + EXPECT_EQ(FormatMode::kSInt, segs[0].GetFormatMode()); + EXPECT_EQ(4, segs[0].SizeInBytes()); + /* a */ + EXPECT_EQ(FormatMode::kSInt, segs[1].GetFormatMode()); + EXPECT_EQ(4, segs[1].SizeInBytes()); + /* b */ + EXPECT_EQ(FormatMode::kSInt, segs[2].GetFormatMode()); + EXPECT_EQ(4, segs[2].SizeInBytes()); + /* c[0] */ + EXPECT_EQ(FormatMode::kSFloat, segs[3].GetFormatMode()); + EXPECT_EQ(4, segs[3].SizeInBytes()); + /* c[1] */ + EXPECT_EQ(FormatMode::kSFloat, segs[4].GetFormatMode()); + EXPECT_EQ(4, segs[4].SizeInBytes()); + /* c[2] */ + EXPECT_EQ(FormatMode::kSFloat, segs[5].GetFormatMode()); + EXPECT_EQ(4, segs[5].SizeInBytes()); + /* y */ + EXPECT_EQ(FormatMode::kSFloat, segs[6].GetFormatMode()); + EXPECT_EQ(4, segs[6].SizeInBytes()); +} + } // namespace amber diff --git a/src/pipeline.cc b/src/pipeline.cc index 5d0d030..8f23ca0 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -18,8 +18,8 @@ #include <limits> #include <set> -#include "src/format_parser.h" #include "src/make_unique.h" +#include "src/type_parser.h" namespace amber { namespace { @@ -311,26 +311,30 @@ Result Pipeline::SetPushConstantBuffer(Buffer* buf) { } std::unique_ptr<Buffer> Pipeline::GenerateDefaultColorAttachmentBuffer() { - FormatParser fp; - auto fmt = fp.Parse(kDefaultColorBufferFormat); + TypeParser parser; + auto type = parser.Parse(kDefaultColorBufferFormat); + auto fmt = MakeUnique<Format>(type.get()); std::unique_ptr<Buffer> buf = MakeUnique<Buffer>(BufferType::kColor); buf->SetName(kGeneratedColorBuffer); buf->SetFormat(fmt.get()); formats_.push_back(std::move(fmt)); + types_.push_back(std::move(type)); return buf; } std::unique_ptr<Buffer> Pipeline::GenerateDefaultDepthAttachmentBuffer() { - FormatParser fp; - auto fmt = fp.Parse(kDefaultDepthBufferFormat); + TypeParser parser; + auto type = parser.Parse(kDefaultDepthBufferFormat); + auto fmt = MakeUnique<Format>(type.get()); std::unique_ptr<Buffer> buf = MakeUnique<Buffer>(BufferType::kDepth); buf->SetName(kGeneratedDepthBuffer); buf->SetFormat(fmt.get()); formats_.push_back(std::move(fmt)); + types_.push_back(std::move(type)); return buf; } @@ -548,10 +552,12 @@ Result Pipeline::GenerateOpenCLPodBuffers() { // Use an 8-bit type because all the data in the descriptor map is // byte-based and it simplifies the logic for sizing below. - FormatParser fp; - auto fmt = fp.Parse("R8_UINT"); + TypeParser parser; + auto type = parser.Parse("R8_UINT"); + auto fmt = MakeUnique<Format>(type.get()); buffer->SetFormat(fmt.get()); formats_.push_back(std::move(fmt)); + types_.push_back(std::move(type)); buffer->SetName(GetName() + "_pod_buffer_" + std::to_string(descriptor_set) + "_" + diff --git a/src/pipeline.h b/src/pipeline.h index a13347c..e874613 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -271,6 +271,7 @@ class Pipeline { std::vector<BufferInfo> color_attachments_; std::vector<BufferInfo> vertex_buffers_; std::vector<BufferInfo> buffers_; + std::vector<std::unique_ptr<type::Type>> types_; std::vector<std::unique_ptr<Format>> formats_; BufferInfo depth_buffer_; BufferInfo push_constant_buffer_; diff --git a/src/pipeline_test.cc b/src/pipeline_test.cc index 55d86e5..dd5064b 100644 --- a/src/pipeline_test.cc +++ b/src/pipeline_test.cc @@ -15,8 +15,8 @@ #include "src/pipeline.h" #include "gtest/gtest.h" -#include "src/format_parser.h" #include "src/make_unique.h" +#include "src/type_parser.h" namespace amber { namespace { @@ -525,9 +525,11 @@ TEST_F(PipelineTest, OpenCLGeneratePodBuffers) { Value int_value; int_value.SetIntValue(1); - FormatParser fp; - auto int_fmt = fp.Parse("R32_SINT"); - auto char_fmt = fp.Parse("R8_SINT"); + TypeParser parser; + auto int_type = parser.Parse("R32_SINT"); + auto int_fmt = MakeUnique<Format>(int_type.get()); + auto char_type = parser.Parse("R8_SINT"); + auto char_fmt = MakeUnique<Format>(char_type.get()); Pipeline::ArgSetInfo arg_info1; arg_info1.name = "arg_a"; @@ -589,8 +591,9 @@ TEST_F(PipelineTest, OpenCLGeneratePodBuffersBadName) { Value int_value; int_value.SetIntValue(1); - FormatParser fp; - auto int_fmt = fp.Parse("R32_SINT"); + TypeParser parser; + auto int_type = parser.Parse("R32_SINT"); + auto int_fmt = MakeUnique<Format>(int_type.get()); Pipeline::ArgSetInfo arg_info1; arg_info1.name = "arg_z"; @@ -631,8 +634,9 @@ TEST_F(PipelineTest, OpenCLGeneratePodBuffersBadSize) { Value int_value; int_value.SetIntValue(1); - FormatParser fp; - auto short_fmt = fp.Parse("R16_SINT"); + TypeParser parser; + auto short_type = parser.Parse("R16_SINT"); + auto short_fmt = MakeUnique<Format>(short_type.get()); Pipeline::ArgSetInfo arg_info1; arg_info1.name = ""; @@ -691,9 +695,11 @@ TEST_F(PipelineTest, OpenCLClone) { Value int_value; int_value.SetIntValue(1); - FormatParser fp; - auto int_fmt = fp.Parse("R32_SINT"); - auto char_fmt = fp.Parse("R8_SINT"); + TypeParser parser; + auto int_type = parser.Parse("R32_SINT"); + auto int_fmt = MakeUnique<Format>(int_type.get()); + auto char_type = parser.Parse("R8_SINT"); + auto char_fmt = MakeUnique<Format>(char_type.get()); Pipeline::ArgSetInfo arg_info1; arg_info1.name = "arg_a"; diff --git a/src/script.h b/src/script.h index 62b4433..51cf70e 100644 --- a/src/script.h +++ b/src/script.h @@ -171,11 +171,18 @@ class Script : public RecipeImpl { /// Retrieves the SPIR-V target environment. const std::string& GetSpvTargetEnv() const { return spv_env_; } + /// Assign ownership of the format to the script. Format* RegisterFormat(std::unique_ptr<Format> fmt) { formats_.push_back(std::move(fmt)); return formats_.back().get(); } + /// Assigns ownership of the type to the script. + type::Type* RegisterType(std::unique_ptr<type::Type> type) { + types_.push_back(std::move(type)); + return types_.back().get(); + } + private: struct { std::vector<std::string> required_features; @@ -192,6 +199,7 @@ class Script : public RecipeImpl { std::vector<std::unique_ptr<Command>> commands_; std::vector<std::unique_ptr<Buffer>> buffers_; std::vector<std::unique_ptr<Pipeline>> pipelines_; + std::vector<std::unique_ptr<type::Type>> types_; std::vector<std::unique_ptr<Format>> formats_; }; diff --git a/src/type.cc b/src/type.cc new file mode 100644 index 0000000..f25e79f --- /dev/null +++ b/src/type.cc @@ -0,0 +1,101 @@ +// 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 +// +// http://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. + +#include "src/type.h" + +#include <cassert> +#include <memory> + +#include "src/make_unique.h" + +namespace amber { +namespace type { + +Type::Type() = default; + +Type::~Type() = default; + +List* Type::AsList() { + return static_cast<List*>(this); +} + +Number* Type::AsNumber() { + return static_cast<Number*>(this); +} + +Struct* Type::AsStruct() { + return static_cast<Struct*>(this); +} + +const List* Type::AsList() const { + return static_cast<const List*>(this); +} + +const Number* Type::AsNumber() const { + return static_cast<const Number*>(this); +} + +const Struct* Type::AsStruct() const { + return static_cast<const Struct*>(this); +} + +// static +std::unique_ptr<Number> Number::Int(uint32_t bits) { + return MakeUnique<Number>(FormatMode::kSInt, bits); +} + +// static +std::unique_ptr<Number> Number::Uint(uint32_t bits) { + return MakeUnique<Number>(FormatMode::kUInt, bits); +} + +// static +std::unique_ptr<Number> Number::Float(uint32_t bits) { + return MakeUnique<Number>(FormatMode::kSFloat, bits); +} + +Number::Number(FormatMode format_mode) : format_mode_(format_mode) {} + +Number::Number(FormatMode format_mode, uint32_t bits) + : format_mode_(format_mode), bits_(bits) {} + +Number::~Number() = default; + +List::List() = default; + +List::~List() = default; + +uint32_t List::SizeInBytes() const { + if (pack_size_in_bits_ > 0) + return pack_size_in_bits_; + + uint32_t size = 0; + for (const auto& member : members_) + size += member.SizeInBytes(); + + return size; +} + +Struct::Struct() = default; + +Struct::~Struct() = default; + +// Struct side is dependent on the layout we're currently in .... +uint32_t Struct::SizeInBytes() const { + assert(false && "Not reached"); + return 0; +} + +} // namespace type +} // namespace amber diff --git a/src/type.h b/src/type.h new file mode 100644 index 0000000..93aba68 --- /dev/null +++ b/src/type.h @@ -0,0 +1,298 @@ +// 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 +// +// http://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. + +#ifndef SRC_TYPE_H_ +#define SRC_TYPE_H_ + +#include <cassert> +#include <memory> +#include <vector> + +#include "src/format_data.h" +#include "src/make_unique.h" + +namespace amber { +namespace type { + +class List; +class Number; +class Struct; + +class Type { + public: + Type(); + virtual ~Type(); + + static bool IsSignedInt(FormatMode mode) { + return mode == FormatMode::kSInt || mode == FormatMode::kSNorm || + mode == FormatMode::kSScaled; + } + + static bool IsUnsignedInt(FormatMode mode) { + return mode == FormatMode::kUInt || mode == FormatMode::kUNorm || + mode == FormatMode::kUScaled || mode == FormatMode::kSRGB; + } + + static bool IsInt(FormatMode mode) { + return IsSignedInt(mode) || IsUnsignedInt(mode); + } + + static bool IsFloat(FormatMode mode) { + return mode == FormatMode::kSFloat || mode == FormatMode::kUFloat; + } + + static bool IsInt8(FormatMode mode, uint32_t num_bits) { + return IsSignedInt(mode) && num_bits == 8; + } + static bool IsInt16(FormatMode mode, uint32_t num_bits) { + return IsSignedInt(mode) && num_bits == 16; + } + static bool IsInt32(FormatMode mode, uint32_t num_bits) { + return IsSignedInt(mode) && num_bits == 32; + } + static bool IsInt64(FormatMode mode, uint32_t num_bits) { + return IsSignedInt(mode) && num_bits == 64; + } + + static bool IsUint8(FormatMode mode, uint32_t num_bits) { + return IsUnsignedInt(mode) && num_bits == 8; + } + static bool IsUint16(FormatMode mode, uint32_t num_bits) { + return IsUnsignedInt(mode) && num_bits == 16; + } + static bool IsUint32(FormatMode mode, uint32_t num_bits) { + return IsUnsignedInt(mode) && num_bits == 32; + } + static bool IsUint64(FormatMode mode, uint32_t num_bits) { + return IsUnsignedInt(mode) && num_bits == 64; + } + + static bool IsFloat16(FormatMode mode, uint32_t num_bits) { + return IsFloat(mode) && num_bits == 16; + } + static bool IsFloat32(FormatMode mode, uint32_t num_bits) { + return IsFloat(mode) && num_bits == 32; + } + static bool IsFloat64(FormatMode mode, uint32_t num_bits) { + return IsFloat(mode) && num_bits == 64; + } + + // Returns the size in bytes of a single element of the type. This does not + // include space for arrays, vectors, etc. + virtual uint32_t SizeInBytes() const = 0; + + virtual bool Equal(const Type* b) const = 0; + + virtual bool IsList() const { return false; } + virtual bool IsNumber() const { return false; } + virtual bool IsStruct() const { return false; } + + List* AsList(); + Number* AsNumber(); + Struct* AsStruct(); + + const List* AsList() const; + const Number* AsNumber() const; + const Struct* AsStruct() const; + + void SetRowCount(uint32_t size) { row_count_ = size; } + uint32_t RowCount() const { return row_count_; } + + void SetColumnCount(uint32_t size) { column_count_ = size; } + uint32_t ColumnCount() const { return column_count_; } + + void SetIsRuntimeArray() { is_array_ = true; } + void SetIsSizedArray(uint32_t size) { + is_array_ = true; + array_size_ = size; + } + bool IsArray() const { return is_array_; } + bool IsSizedArray() const { return is_array_ && array_size_ > 0; } + bool IsRuntimeArray() const { return is_array_ && array_size_ == 0; } + uint32_t ArraySize() const { return array_size_; } + + bool IsVec() const { return column_count_ == 1 && row_count_ > 1; } + + // Returns true if this type holds a vec3. + bool IsVec3() const { return column_count_ == 1 && row_count_ == 3; } + + // Returns true if this type holds a matrix. + bool IsMatrix() const { return column_count_ > 1 && row_count_ > 1; } + + private: + uint32_t row_count_ = 1; + uint32_t column_count_ = 1; + uint32_t array_size_ = 0; + bool is_array_ = false; +}; + +class Number : public Type { + public: + explicit Number(FormatMode mode); + Number(FormatMode mode, uint32_t bits); + ~Number() override; + + static std::unique_ptr<Number> Int(uint32_t bits); + static std::unique_ptr<Number> Uint(uint32_t bits); + static std::unique_ptr<Number> Float(uint32_t bits); + + bool IsNumber() const override { return true; } + + uint32_t NumBits() const { return bits_; } + uint32_t SizeInBytes() const override { return bits_ / 8; } + + bool Equal(const Type* b) const override { + if (!b->IsNumber()) + return false; + + auto n = b->AsNumber(); + return format_mode_ == n->format_mode_ && bits_ == n->bits_; + } + + FormatMode GetFormatMode() const { return format_mode_; } + + private: + FormatMode format_mode_ = FormatMode::kSInt; + uint32_t bits_ = 32; +}; + +// The list type only holds lists of scalar float and int values. +class List : public Type { + public: + struct Member { + Member(FormatComponentType t, FormatMode m, uint32_t b) + : name(t), mode(m), num_bits(b) {} + + uint32_t SizeInBytes() const { return num_bits / 8; } + + FormatComponentType name = FormatComponentType::kR; + FormatMode mode = FormatMode::kSInt; + uint32_t num_bits = 0; + }; + + List(); + ~List() override; + + bool IsList() const override { return true; } + + bool Equal(const Type* b) const override { + if (!b->IsList()) + return false; + + auto l = b->AsList(); + if (pack_size_in_bits_ != l->pack_size_in_bits_) + return false; + if (members_.size() != l->members_.size()) + return false; + + auto& lm = l->Members(); + for (size_t i = 0; i < members_.size(); ++i) { + if (members_[i].name != lm[i].name) + return false; + if (members_[i].mode != lm[i].mode) + return false; + if (members_[i].num_bits != lm[i].num_bits) + return false; + } + return true; + } + + void SetPackSizeInBits(uint32_t size) { pack_size_in_bits_ = size; } + uint32_t PackSizeInBits() const { return pack_size_in_bits_; } + bool IsPacked() const { return pack_size_in_bits_ > 0; } + + void AddMember(FormatComponentType name, FormatMode mode, uint32_t num_bits) { + members_.push_back({name, mode, num_bits}); + } + + const std::vector<Member>& Members() const { return members_; } + std::vector<Member>& Members() { return members_; } + + uint32_t SizeInBytes() const override; + + private: + std::vector<Member> members_; + uint32_t pack_size_in_bits_ = 0; +}; + +class Struct : public Type { + public: + struct Member { + Type* type; + int32_t offset_in_bytes = -1; + int32_t array_stride_in_bytes = -1; + int32_t matrix_stride_in_bytes = -1; + + bool HasOffset() const { return offset_in_bytes >= 0; } + bool HasArrayStride() const { return array_stride_in_bytes > 0; } + bool HasMatrixStride() const { return matrix_stride_in_bytes > 0; } + }; + + Struct(); + ~Struct() override; + + uint32_t SizeInBytes() const override; + bool IsStruct() const override { return true; } + + bool Equal(const Type* b) const override { + if (!b->IsStruct()) + return false; + + auto s = b->AsStruct(); + if (is_stride_specified_ != s->is_stride_specified_) + return false; + if (stride_in_bytes_ != s->stride_in_bytes_) + return false; + if (members_.size() != s->members_.size()) + return false; + + auto& sm = s->Members(); + for (size_t i = 0; i < members_.size(); ++i) { + if (members_[i].offset_in_bytes != sm[i].offset_in_bytes) + return false; + if (members_[i].array_stride_in_bytes != sm[i].array_stride_in_bytes) + return false; + if (members_[i].matrix_stride_in_bytes != sm[i].matrix_stride_in_bytes) + return false; + if (!members_[i].type->Equal(sm[i].type)) + return false; + } + return true; + } + + bool HasStride() const { return is_stride_specified_; } + uint32_t StrideInBytes() const { return stride_in_bytes_; } + void SetStrideInBytes(uint32_t stride) { + is_stride_specified_ = true; + stride_in_bytes_ = stride; + } + + Member* AddMember(Type* type) { + members_.push_back({}); + members_.back().type = type; + return &members_.back(); + } + + const std::vector<Member>& Members() const { return members_; } + + private: + std::vector<Member> members_; + bool is_stride_specified_ = false; + uint32_t stride_in_bytes_ = 0; +}; + +} // namespace type +} // namespace amber + +#endif // SRC_TYPE_H_ diff --git a/src/format_parser.cc b/src/type_parser.cc index b0e51fb..a6779f0 100644 --- a/src/format_parser.cc +++ b/src/type_parser.cc @@ -12,20 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "src/format_parser.h" +#include "src/type_parser.h" #include <cassert> #include <cstdlib> +#include <string> #include "src/make_unique.h" namespace amber { -FormatParser::FormatParser() = default; +TypeParser::TypeParser() = default; -FormatParser::~FormatParser() = default; +TypeParser::~TypeParser() = default; -std::unique_ptr<Format> FormatParser::Parse(const std::string& data) { +std::unique_ptr<type::Type> TypeParser::Parse(const std::string& data) { if (data.empty()) return nullptr; @@ -33,50 +34,60 @@ std::unique_ptr<Format> FormatParser::Parse(const std::string& data) { if (data.find('/', 0) != std::string::npos) return ParseGlslFormat(data); - FormatType type = NameToType(data); - if (type == FormatType::kUnknown) - return nullptr; + // Walk the string backwards. This means we'll know if it's pack and we'll + // know the mode before we get to a given named component. + size_t cur_pos = std::string::npos; + for (;;) { + size_t next_pos = data.rfind('_', cur_pos); + if (next_pos == std::string::npos) { + if (cur_pos != std::string::npos) + ProcessChunk(data.substr(0, cur_pos + 1)); + break; + } - auto fmt = MakeUnique<Format>(); - fmt->SetFormatType(type); + ProcessChunk(data.substr(next_pos + 1, cur_pos - next_pos)); + cur_pos = next_pos - 1; + } - size_t cur_pos = 0; - while (cur_pos < data.length()) { - size_t next_pos = data.find('_', cur_pos); - if (next_pos == std::string::npos) - next_pos = data.length(); + if (pieces_.empty()) + return nullptr; - ProcessChunk(fmt.get(), data.substr(cur_pos, next_pos - cur_pos).c_str()); - cur_pos = next_pos + 1; + std::unique_ptr<type::Type> type = nullptr; + if (pack_size_ == 0 && pieces_.size() == 1 && + pieces_[0].type == FormatComponentType::kR) { + type = MakeUnique<type::Number>(pieces_[0].mode, pieces_[0].num_bits); + } else { + type = MakeUnique<type::List>(); + type->SetRowCount(static_cast<uint32_t>(pieces_.size())); + type->AsList()->SetPackSizeInBits(pack_size_); + + for (const auto& piece : pieces_) + type->AsList()->AddMember(piece.type, piece.mode, piece.num_bits); } - assert(pieces_.empty()); - - return fmt; -} + pack_size_ = 0; + mode_ = FormatMode::kSInt; + pieces_.clear(); -void FormatParser::AddPiece(FormatComponentType type, uint8_t bits) { - pieces_.emplace_back(type, bits); + return type; } -void FormatParser::FlushPieces(Format* fmt, FormatMode mode) { - for (const auto& piece : pieces_) - fmt->AddComponent(piece.type, mode, piece.num_bits); - - pieces_.clear(); +void TypeParser::AddPiece(FormatComponentType type, + FormatMode mode, + uint8_t bits) { + pieces_.insert(pieces_.begin(), Pieces{type, mode, bits}); } -// TODO(dsinclair): Remove asserts return something ...? -void FormatParser::ProcessChunk(Format* fmt, const std::string& data) { +void TypeParser::ProcessChunk(const std::string& data) { assert(data.size() > 0); if (data[0] == 'P') { if (data == "PACK8") - fmt->SetPackSize(8); + pack_size_ = 8; else if (data == "PACK16") - fmt->SetPackSize(16); + pack_size_ = 16; else if (data == "PACK32") - fmt->SetPackSize(32); + pack_size_ = 32; else assert(false); @@ -85,13 +96,13 @@ void FormatParser::ProcessChunk(Format* fmt, const std::string& data) { if (data[0] == 'U') { if (data == "UINT") - FlushPieces(fmt, FormatMode::kUInt); + mode_ = FormatMode::kUInt; else if (data == "UNORM") - FlushPieces(fmt, FormatMode::kUNorm); + mode_ = FormatMode::kUNorm; else if (data == "UFLOAT") - FlushPieces(fmt, FormatMode::kUFloat); + mode_ = FormatMode::kUFloat; else if (data == "USCALED") - FlushPieces(fmt, FormatMode::kUScaled); + mode_ = FormatMode::kUScaled; else assert(false); @@ -100,63 +111,66 @@ void FormatParser::ProcessChunk(Format* fmt, const std::string& data) { if (data[0] == 'S') { if (data == "SINT") - FlushPieces(fmt, FormatMode::kSInt); + mode_ = FormatMode::kSInt; else if (data == "SNORM") - FlushPieces(fmt, FormatMode::kSNorm); + mode_ = FormatMode::kSNorm; else if (data == "SSCALED") - FlushPieces(fmt, FormatMode::kSScaled); + mode_ = FormatMode::kSScaled; else if (data == "SFLOAT") - FlushPieces(fmt, FormatMode::kSFloat); + mode_ = FormatMode::kSFloat; else if (data == "SRGB") - FlushPieces(fmt, FormatMode::kSRGB); + mode_ = FormatMode::kSRGB; else if (data == "S8") - AddPiece(FormatComponentType::kS, 8); + AddPiece(FormatComponentType::kS, mode_, 8); else assert(false); return; } - size_t cur_pos = 0; - while (cur_pos < data.size()) { + int32_t cur_pos = static_cast<int32_t>(data.size()) - 1; + for (;;) { FormatComponentType type = FormatComponentType::kA; - switch (data[cur_pos++]) { - case 'X': + while (cur_pos >= 0) { + if (data[static_cast<size_t>(cur_pos)] == 'X') { type = FormatComponentType::kX; break; - case 'D': + } else if (data[static_cast<size_t>(cur_pos)] == 'D') { type = FormatComponentType::kD; break; - case 'R': + } else if (data[static_cast<size_t>(cur_pos)] == 'R') { type = FormatComponentType::kR; break; - case 'G': + } else if (data[static_cast<size_t>(cur_pos)] == 'G') { type = FormatComponentType::kG; break; - case 'B': + } else if (data[static_cast<size_t>(cur_pos)] == 'B') { type = FormatComponentType::kB; break; - case 'A': + } else if (data[static_cast<size_t>(cur_pos)] == 'A') { type = FormatComponentType::kA; break; - default: - assert(false); + } + --cur_pos; } - - assert(cur_pos < data.size()); + assert(cur_pos >= 0); char* next_str; - const char* str = data.c_str() + cur_pos; + const char* str = data.c_str() + cur_pos + 1; uint64_t val = static_cast<uint64_t>(std::strtol(str, &next_str, 10)); - AddPiece(type, static_cast<uint8_t>(val)); + if (val > 0) + AddPiece(type, mode_, static_cast<uint8_t>(val)); + + if (cur_pos == 0) + break; - cur_pos += static_cast<size_t>(next_str - str); + --cur_pos; } } // static -FormatType FormatParser::NameToType(const std::string& data) { +FormatType TypeParser::NameToFormatType(const std::string& data) { if (data == "A1R5G5B5_UNORM_PACK16") return FormatType::kA1R5G5B5_UNORM_PACK16; if (data == "A2B10G10R10_SINT_PACK32") @@ -419,7 +433,8 @@ FormatType FormatParser::NameToType(const std::string& data) { return FormatType::kUnknown; } -std::unique_ptr<Format> FormatParser::ParseGlslFormat(const std::string& fmt) { +std::unique_ptr<type::Type> TypeParser::ParseGlslFormat( + const std::string& fmt) { size_t pos = fmt.find('/'); std::string gl_type = fmt.substr(0, pos); std::string glsl_type = fmt.substr(pos + 1); diff --git a/src/type_parser.h b/src/type_parser.h new file mode 100644 index 0000000..d737e86 --- /dev/null +++ b/src/type_parser.h @@ -0,0 +1,64 @@ +// 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 +// +// http://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. + +#ifndef SRC_TYPE_PARSER_H_ +#define SRC_TYPE_PARSER_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "src/type.h" + +namespace amber { + +/// Parses a Vulkan image string into a type object. +class TypeParser { + public: + static FormatType NameToFormatType(const std::string& data); + + TypeParser(); + ~TypeParser(); + + /// Parses the |fmt| string and returns the associated type, nullptr if the + /// conversion is not possible. + /// + /// The format string can come in two different forms, it can be a vulkan + /// style format string (e.g. R32G32B32A32_SFLOAT) or it can be in the type + /// format (gl_type/glsl_type) specified by VkScript (e.g. byte/vec4). + std::unique_ptr<type::Type> Parse(const std::string& fmt); + + private: + std::unique_ptr<type::Type> ParseGlslFormat(const std::string& fmt); + void ProcessChunk(const std::string&); + void AddPiece(FormatComponentType type, FormatMode mode, uint8_t bits); + void FlushPieces(type::Type* type, FormatMode mode); + + struct Pieces { + Pieces(FormatComponentType t, FormatMode m, uint8_t bits) + : type(t), mode(m), num_bits(bits) {} + + FormatComponentType type; + FormatMode mode; + uint8_t num_bits; + }; + + FormatMode mode_ = FormatMode::kSInt; + uint32_t pack_size_ = 0; + std::vector<Pieces> pieces_; +}; + +} // namespace amber + +#endif // SRC_TYPE_PARSER_H_ diff --git a/src/format_parser_test.cc b/src/type_parser_test.cc index bb42553..c26c329 100644 --- a/src/format_parser_test.cc +++ b/src/type_parser_test.cc @@ -12,15 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "src/format_parser.h" +#include "src/type_parser.h" #include "gtest/gtest.h" +#include "src/format.h" namespace amber { -using FormatParserTest = testing::Test; +using TypeParserTest = testing::Test; -TEST_F(FormatParserTest, Formats) { +TEST_F(TypeParserTest, Formats) { struct { const char* name; FormatType type; @@ -1175,71 +1176,77 @@ TEST_F(FormatParserTest, Formats) { }}, }; - for (const auto& fmt : formats) { - FormatParser parser; - auto format = parser.Parse(fmt.name); + for (const auto& data : formats) { + TypeParser parser; + auto type = parser.Parse(data.name); - ASSERT_TRUE(format != nullptr) << fmt.name; - EXPECT_EQ(fmt.type, format->GetFormatType()) << fmt.name; - EXPECT_EQ(fmt.pack_size, format->GetPackSize()) << fmt.name; + ASSERT_TRUE(type != nullptr) << data.name; - auto& segs = format->GetSegments(); - ASSERT_TRUE(fmt.component_count <= segs.size()) << fmt.name; + Format fmt(type.get()); + EXPECT_EQ(data.type, fmt.GetFormatType()) << data.name; + if (data.pack_size > 0) { + ASSERT_TRUE(fmt.GetType()->IsList()); + ASSERT_TRUE(fmt.GetType()->AsList()->IsPacked()); + EXPECT_EQ(data.pack_size, fmt.GetType()->AsList()->PackSizeInBits()); - for (size_t i = 0; i < fmt.component_count; ++i) { - EXPECT_EQ(fmt.components[i].type, segs[i].GetComponent()->type) - << fmt.name; - EXPECT_EQ(fmt.components[i].mode, segs[i].GetComponent()->mode) - << fmt.name; - EXPECT_EQ(fmt.components[i].num_bits, segs[i].GetComponent()->num_bits) - << fmt.name; - } + const auto& members = fmt.GetType()->AsList()->Members(); + for (size_t i = 0; i < data.component_count; ++i) { + EXPECT_EQ(data.components[i].type, members[i].name) << data.name; + EXPECT_EQ(data.components[i].mode, members[i].mode) << data.name; + EXPECT_EQ(data.components[i].num_bits, members[i].num_bits) + << data.name; + } + } else { + auto& segs = fmt.GetSegments(); + ASSERT_TRUE(data.component_count <= segs.size()) << data.name; + + for (size_t i = 0; i < data.component_count; ++i) { + EXPECT_EQ(data.components[i].mode, segs[i].GetFormatMode()); + EXPECT_EQ(data.components[i].num_bits, segs[i].GetNumBits()) + << data.name; + } - if (fmt.component_count < segs.size()) { - // Only one padding added - EXPECT_EQ(1, segs.size() - fmt.component_count); - EXPECT_TRUE(segs.back().IsPadding()); + if (data.component_count < segs.size()) { + // Only one padding added + EXPECT_EQ(1, segs.size() - data.component_count); + EXPECT_TRUE(segs.back().IsPadding()); + } } } } // NOLINT(readability/fn_size) -TEST_F(FormatParserTest, InvalidFormat) { - FormatParser parser; - auto format = parser.Parse("BLAH_BLAH_BLAH"); - EXPECT_TRUE(format == nullptr); +TEST_F(TypeParserTest, InvalidFormat) { + TypeParser parser; + auto type = parser.Parse("BLAH_BLAH_BLAH"); + EXPECT_TRUE(type == nullptr); } -TEST_F(FormatParserTest, EmptyFormat) { - FormatParser parser; - auto format = parser.Parse(""); - EXPECT_TRUE(format == nullptr); +TEST_F(TypeParserTest, EmptyFormat) { + TypeParser parser; + auto type = parser.Parse(""); + EXPECT_TRUE(type == nullptr); } -TEST_F(FormatParserTest, GlslString) { - FormatParser parser; - auto format = parser.Parse("float/vec3"); - ASSERT_TRUE(format != nullptr); +TEST_F(TypeParserTest, GlslString) { + TypeParser parser; + auto type = parser.Parse("float/vec3"); + ASSERT_TRUE(type != nullptr); - EXPECT_EQ(FormatType::kR32G32B32_SFLOAT, format->GetFormatType()); - EXPECT_EQ(static_cast<size_t>(0U), format->GetPackSize()); + Format fmt(type.get()); + EXPECT_EQ(FormatType::kR32G32B32_SFLOAT, fmt.GetFormatType()); - auto& segs = format->GetSegments(); + auto& segs = fmt.GetSegments(); ASSERT_EQ(4U, segs.size()); - EXPECT_EQ(FormatComponentType::kR, segs[0].GetComponent()->type); - EXPECT_EQ(FormatMode::kSFloat, segs[0].GetComponent()->mode); - EXPECT_EQ(32U, segs[0].GetComponent()->num_bits); - EXPECT_EQ(FormatComponentType::kG, segs[1].GetComponent()->type); - EXPECT_EQ(FormatMode::kSFloat, segs[1].GetComponent()->mode); - EXPECT_EQ(32U, segs[1].GetComponent()->num_bits); - EXPECT_EQ(FormatComponentType::kB, segs[2].GetComponent()->type); - EXPECT_EQ(FormatMode::kSFloat, segs[2].GetComponent()->mode); - EXPECT_EQ(32U, segs[2].GetComponent()->num_bits); + for (size_t i = 0; i < 3; ++i) { + EXPECT_TRUE( + type::Type::IsFloat32(segs[i].GetFormatMode(), segs[i].GetNumBits())); + } EXPECT_TRUE(segs[3].IsPadding()); } -TEST_F(FormatParserTest, GlslStrings) { +TEST_F(TypeParserTest, GlslStrings) { struct { const char* name; FormatType type; @@ -1260,15 +1267,16 @@ TEST_F(FormatParserTest, GlslStrings) { }; for (const auto& str : strs) { - FormatParser parser; - auto format = parser.Parse(str.name); - ASSERT_FALSE(format == nullptr); + TypeParser parser; + auto type = parser.Parse(str.name); + ASSERT_FALSE(type == nullptr); - EXPECT_EQ(str.type, format->GetFormatType()) << str.name; + Format fmt(type.get()); + EXPECT_EQ(str.type, fmt.GetFormatType()) << str.name; } } -TEST_F(FormatParserTest, GlslStringInvalid) { +TEST_F(TypeParserTest, GlslStringInvalid) { struct { const char* name; } strs[] = { @@ -1279,9 +1287,9 @@ TEST_F(FormatParserTest, GlslStringInvalid) { }; for (const auto& str : strs) { - FormatParser parser; - auto format = parser.Parse(str.name); - EXPECT_TRUE(format == nullptr); + TypeParser parser; + auto fmt = parser.Parse(str.name); + EXPECT_TRUE(fmt == nullptr); } } diff --git a/src/type_test.cc b/src/type_test.cc new file mode 100644 index 0000000..bc140d4 --- /dev/null +++ b/src/type_test.cc @@ -0,0 +1,399 @@ +// 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 +// +// http://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. + +#include "src/type.h" + +#include "gtest/gtest.h" + +namespace amber { +namespace type { + +using TypeTest = testing::Test; + +TEST_F(TypeTest, IsArray) { + Number i(FormatMode::kSInt, 16); + + EXPECT_FALSE(i.IsArray()); + EXPECT_FALSE(i.IsRuntimeArray()); + EXPECT_FALSE(i.IsSizedArray()); + + i.SetIsRuntimeArray(); + EXPECT_TRUE(i.IsArray()); + EXPECT_TRUE(i.IsRuntimeArray()); + EXPECT_FALSE(i.IsSizedArray()); + + i.SetIsSizedArray(3); + EXPECT_TRUE(i.IsArray()); + EXPECT_FALSE(i.IsRuntimeArray()); + EXPECT_TRUE(i.IsSizedArray()); + EXPECT_EQ(3, i.ArraySize()); +} + +TEST_F(TypeTest, IsStruct) { + EXPECT_FALSE(Number(FormatMode::kSInt).IsStruct()); + EXPECT_TRUE(Struct().IsStruct()); + EXPECT_FALSE(List().IsStruct()); +} + +TEST_F(TypeTest, IsNumber) { + EXPECT_TRUE(Number(FormatMode::kSInt).IsNumber()); + EXPECT_FALSE(Struct().IsNumber()); + EXPECT_FALSE(List().IsNumber()); +} + +TEST_F(TypeTest, IsList) { + EXPECT_FALSE(Number(FormatMode::kSInt).IsList()); + EXPECT_FALSE(Struct().IsList()); + EXPECT_TRUE(List().IsList()); +} + +TEST_F(TypeTest, Vectors) { + Number i(FormatMode::kSInt, 16); + i.SetRowCount(2); + + EXPECT_EQ(2, i.RowCount()); + EXPECT_TRUE(i.IsVec()); + EXPECT_FALSE(i.IsVec3()); + EXPECT_FALSE(i.IsMatrix()); + + i.SetColumnCount(3); + EXPECT_FALSE(i.IsVec3()); +} + +TEST_F(TypeTest, Matrix) { + Number i(FormatMode::kSInt, 16); + i.SetColumnCount(2); + i.SetRowCount(2); + + EXPECT_EQ(2, i.ColumnCount()); + EXPECT_EQ(2, i.RowCount()); + + EXPECT_FALSE(i.IsVec()); + EXPECT_TRUE(i.IsMatrix()); +} + +TEST_F(TypeTest, SizeInBytesForVector) { + Number i(FormatMode::kSInt, 32); + uint32_t bytes = i.SizeInBytes(); + + i.SetRowCount(3); + EXPECT_EQ(bytes, i.SizeInBytes()); +} + +TEST_F(TypeTest, SizeInBytesForMatrix) { + Number i(FormatMode::kSInt, 32); + uint32_t bytes = i.SizeInBytes(); + + i.SetColumnCount(3); + i.SetRowCount(3); + EXPECT_EQ(bytes, i.SizeInBytes()); +} + +TEST_F(TypeTest, SizeInBytesForArray) { + Number i(FormatMode::kSInt, 32); + uint32_t bytes = i.SizeInBytes(); + + i.SetIsSizedArray(3); + EXPECT_EQ(bytes, i.SizeInBytes()); +} + +TEST_F(TypeTest, NumberEqual) { + Number n1(FormatMode::kSFloat, 32); + Number n2(FormatMode::kSFloat, 32); + Number n3(FormatMode::kSFloat, 16); + Number n4(FormatMode::kSInt, 32); + + List l; + Struct s; + + EXPECT_TRUE(n1.Equal(&n2)); + EXPECT_FALSE(n1.Equal(&n3)); + EXPECT_FALSE(n1.Equal(&n4)); + EXPECT_FALSE(n1.Equal(&l)); + EXPECT_FALSE(n1.Equal(&s)); +} + +TEST_F(TypeTest, ListPacked) { + List l; + EXPECT_FALSE(l.IsPacked()); + EXPECT_EQ(0U, l.PackSizeInBits()); + + l.SetPackSizeInBits(32); + EXPECT_TRUE(l.IsPacked()); + EXPECT_EQ(32U, l.PackSizeInBits()); +} + +TEST_F(TypeTest, ListEqual) { + List l1; + List l2; + + l1.AddMember(FormatComponentType::kR, FormatMode::kSFloat, 32); + l2.AddMember(FormatComponentType::kR, FormatMode::kSFloat, 32); + EXPECT_TRUE(l1.Equal(&l2)); + + l2.SetPackSizeInBits(24); + EXPECT_FALSE(l1.Equal(&l2)); + + List l3; + l3.AddMember(FormatComponentType::kR, FormatMode::kSFloat, 16); + EXPECT_FALSE(l1.Equal(&l3)); + + List l4; + l4.AddMember(FormatComponentType::kR, FormatMode::kSInt, 16); + EXPECT_FALSE(l1.Equal(&l4)); + + List l5; + l5.AddMember(FormatComponentType::kG, FormatMode::kSFloat, 32); + EXPECT_FALSE(l1.Equal(&l5)); + + List l6; + l6.AddMember(FormatComponentType::kR, FormatMode::kSFloat, 32); + l6.AddMember(FormatComponentType::kG, FormatMode::kSFloat, 32); + EXPECT_FALSE(l1.Equal(&l6)); +} + +TEST_F(TypeTest, StructStride) { + Struct s; + EXPECT_FALSE(s.HasStride()); + EXPECT_EQ(0U, s.StrideInBytes()); + + s.SetStrideInBytes(32); + EXPECT_TRUE(s.HasStride()); + EXPECT_EQ(32U, s.StrideInBytes()); +} + +TEST_F(TypeTest, StructEqual) { + Struct s1; + Struct s2; + + auto num32 = Number::Float(32); + auto m1 = s1.AddMember(num32.get()); + s2.AddMember(num32.get()); + EXPECT_TRUE(s1.Equal(&s2)); + + s2.SetStrideInBytes(20); + EXPECT_FALSE(s1.Equal(&s2)); + + Struct s3; + auto num16 = Number::Float(16); + s3.AddMember(num16.get()); + EXPECT_FALSE(s1.Equal(&s3)); + + Struct s4; + auto m = s4.AddMember(num16.get()); + m->offset_in_bytes = 20; + EXPECT_FALSE(s1.Equal(&s4)); + + m->offset_in_bytes = m1->offset_in_bytes; + m->array_stride_in_bytes = 20; + EXPECT_FALSE(s1.Equal(&s4)); + + m->array_stride_in_bytes = m1->array_stride_in_bytes; + m->matrix_stride_in_bytes = 20; + EXPECT_FALSE(s1.Equal(&s4)); +} + +TEST_F(TypeTest, NumberDefault32Bits) { + EXPECT_EQ(4, Number(FormatMode::kUNorm).SizeInBytes()); +} + +TEST_F(TypeTest, NumberInBytes) { + EXPECT_EQ(1, Number(FormatMode::kSInt, 8).SizeInBytes()); + EXPECT_EQ(2, Number(FormatMode::kSInt, 16).SizeInBytes()); + EXPECT_EQ(4, Number(FormatMode::kSInt, 32).SizeInBytes()); + EXPECT_EQ(8, Number(FormatMode::kSInt, 64).SizeInBytes()); +} + +TEST_F(TypeTest, IsInt) { + EXPECT_TRUE(Type::IsInt(FormatMode::kSInt)); + EXPECT_TRUE(Type::IsInt(FormatMode::kSNorm)); + EXPECT_TRUE(Type::IsInt(FormatMode::kSScaled)); + EXPECT_TRUE(Type::IsInt(FormatMode::kSRGB)); + EXPECT_TRUE(Type::IsInt(FormatMode::kUNorm)); + EXPECT_TRUE(Type::IsInt(FormatMode::kUInt)); + EXPECT_TRUE(Type::IsInt(FormatMode::kUScaled)); + EXPECT_FALSE(Type::IsInt(FormatMode::kSFloat)); + EXPECT_FALSE(Type::IsInt(FormatMode::kUFloat)); +} + +TEST_F(TypeTest, IsSignedInt) { + EXPECT_TRUE(Type::IsSignedInt(FormatMode::kSInt)); + EXPECT_TRUE(Type::IsSignedInt(FormatMode::kSNorm)); + EXPECT_TRUE(Type::IsSignedInt(FormatMode::kSScaled)); + EXPECT_FALSE(Type::IsSignedInt(FormatMode::kSRGB)); + EXPECT_FALSE(Type::IsSignedInt(FormatMode::kUNorm)); + EXPECT_FALSE(Type::IsSignedInt(FormatMode::kUInt)); + EXPECT_FALSE(Type::IsSignedInt(FormatMode::kUScaled)); + EXPECT_FALSE(Type::IsSignedInt(FormatMode::kSFloat)); + EXPECT_FALSE(Type::IsSignedInt(FormatMode::kUFloat)); +} + +TEST_F(TypeTest, IsUnsignedInt) { + EXPECT_FALSE(Type::IsUnsignedInt(FormatMode::kSInt)); + EXPECT_FALSE(Type::IsUnsignedInt(FormatMode::kSNorm)); + EXPECT_FALSE(Type::IsUnsignedInt(FormatMode::kSScaled)); + EXPECT_TRUE(Type::IsUnsignedInt(FormatMode::kSRGB)); + EXPECT_TRUE(Type::IsUnsignedInt(FormatMode::kUNorm)); + EXPECT_TRUE(Type::IsUnsignedInt(FormatMode::kUInt)); + EXPECT_TRUE(Type::IsUnsignedInt(FormatMode::kUScaled)); + EXPECT_FALSE(Type::IsUnsignedInt(FormatMode::kSFloat)); + EXPECT_FALSE(Type::IsUnsignedInt(FormatMode::kUFloat)); +} + +TEST_F(TypeTest, IsFloat) { + EXPECT_FALSE(Type::IsFloat(FormatMode::kSInt)); + EXPECT_FALSE(Type::IsFloat(FormatMode::kSNorm)); + EXPECT_FALSE(Type::IsFloat(FormatMode::kSScaled)); + EXPECT_FALSE(Type::IsFloat(FormatMode::kSRGB)); + EXPECT_FALSE(Type::IsFloat(FormatMode::kUNorm)); + EXPECT_FALSE(Type::IsFloat(FormatMode::kUInt)); + EXPECT_FALSE(Type::IsFloat(FormatMode::kUScaled)); + EXPECT_TRUE(Type::IsFloat(FormatMode::kSFloat)); + EXPECT_TRUE(Type::IsFloat(FormatMode::kUFloat)); +} + +TEST_F(TypeTest, IsInt8) { + EXPECT_TRUE(Type::IsInt8(FormatMode::kSInt, 8)); + EXPECT_TRUE(Type::IsInt8(FormatMode::kSNorm, 8)); + EXPECT_TRUE(Type::IsInt8(FormatMode::kSScaled, 8)); + EXPECT_FALSE(Type::IsInt8(FormatMode::kSRGB, 8)); + EXPECT_FALSE(Type::IsInt8(FormatMode::kUNorm, 8)); + EXPECT_FALSE(Type::IsInt8(FormatMode::kUInt, 8)); + EXPECT_FALSE(Type::IsInt8(FormatMode::kUScaled, 8)); + EXPECT_FALSE(Type::IsInt8(FormatMode::kUFloat, 8)); + EXPECT_FALSE(Type::IsInt8(FormatMode::kSFloat, 8)); +} + +TEST_F(TypeTest, IsInt16) { + EXPECT_TRUE(Type::IsInt16(FormatMode::kSInt, 16)); + EXPECT_TRUE(Type::IsInt16(FormatMode::kSNorm, 16)); + EXPECT_TRUE(Type::IsInt16(FormatMode::kSScaled, 16)); + EXPECT_FALSE(Type::IsInt16(FormatMode::kSRGB, 16)); + EXPECT_FALSE(Type::IsInt16(FormatMode::kUNorm, 16)); + EXPECT_FALSE(Type::IsInt16(FormatMode::kUInt, 16)); + EXPECT_FALSE(Type::IsInt16(FormatMode::kUScaled, 16)); + EXPECT_FALSE(Type::IsInt16(FormatMode::kUFloat, 16)); + EXPECT_FALSE(Type::IsInt16(FormatMode::kSFloat, 16)); +} + +TEST_F(TypeTest, IsInt32) { + EXPECT_TRUE(Type::IsInt32(FormatMode::kSInt, 32)); + EXPECT_TRUE(Type::IsInt32(FormatMode::kSNorm, 32)); + EXPECT_TRUE(Type::IsInt32(FormatMode::kSScaled, 32)); + EXPECT_FALSE(Type::IsInt32(FormatMode::kSRGB, 32)); + EXPECT_FALSE(Type::IsInt32(FormatMode::kUNorm, 32)); + EXPECT_FALSE(Type::IsInt32(FormatMode::kUInt, 32)); + EXPECT_FALSE(Type::IsInt32(FormatMode::kUScaled, 32)); + EXPECT_FALSE(Type::IsInt32(FormatMode::kUFloat, 32)); + EXPECT_FALSE(Type::IsInt32(FormatMode::kSFloat, 32)); +} + +TEST_F(TypeTest, IsInt64) { + EXPECT_TRUE(Type::IsInt64(FormatMode::kSInt, 64)); + EXPECT_TRUE(Type::IsInt64(FormatMode::kSNorm, 64)); + EXPECT_TRUE(Type::IsInt64(FormatMode::kSScaled, 64)); + EXPECT_FALSE(Type::IsInt64(FormatMode::kSRGB, 64)); + EXPECT_FALSE(Type::IsInt64(FormatMode::kUNorm, 64)); + EXPECT_FALSE(Type::IsInt64(FormatMode::kUInt, 64)); + EXPECT_FALSE(Type::IsInt64(FormatMode::kUScaled, 64)); + EXPECT_FALSE(Type::IsInt64(FormatMode::kUFloat, 64)); + EXPECT_FALSE(Type::IsInt64(FormatMode::kSFloat, 64)); +} + +TEST_F(TypeTest, IsUint8) { + EXPECT_FALSE(Type::IsUint8(FormatMode::kSInt, 8)); + EXPECT_FALSE(Type::IsUint8(FormatMode::kSNorm, 8)); + EXPECT_FALSE(Type::IsUint8(FormatMode::kSScaled, 8)); + EXPECT_TRUE(Type::IsUint8(FormatMode::kSRGB, 8)); + EXPECT_TRUE(Type::IsUint8(FormatMode::kUNorm, 8)); + EXPECT_TRUE(Type::IsUint8(FormatMode::kUInt, 8)); + EXPECT_TRUE(Type::IsUint8(FormatMode::kUScaled, 8)); + EXPECT_FALSE(Type::IsUint8(FormatMode::kUFloat, 8)); + EXPECT_FALSE(Type::IsUint8(FormatMode::kSFloat, 8)); +} + +TEST_F(TypeTest, IsUint16) { + EXPECT_FALSE(Type::IsUint16(FormatMode::kSInt, 16)); + EXPECT_FALSE(Type::IsUint16(FormatMode::kSNorm, 16)); + EXPECT_FALSE(Type::IsUint16(FormatMode::kSScaled, 16)); + EXPECT_TRUE(Type::IsUint16(FormatMode::kSRGB, 16)); + EXPECT_TRUE(Type::IsUint16(FormatMode::kUNorm, 16)); + EXPECT_TRUE(Type::IsUint16(FormatMode::kUInt, 16)); + EXPECT_TRUE(Type::IsUint16(FormatMode::kUScaled, 16)); + EXPECT_FALSE(Type::IsUint16(FormatMode::kUFloat, 16)); + EXPECT_FALSE(Type::IsUint16(FormatMode::kSFloat, 16)); +} + +TEST_F(TypeTest, IsUint32) { + EXPECT_FALSE(Type::IsUint32(FormatMode::kSInt, 32)); + EXPECT_FALSE(Type::IsUint32(FormatMode::kSNorm, 32)); + EXPECT_FALSE(Type::IsUint32(FormatMode::kSScaled, 32)); + EXPECT_TRUE(Type::IsUint32(FormatMode::kSRGB, 32)); + EXPECT_TRUE(Type::IsUint32(FormatMode::kUNorm, 32)); + EXPECT_TRUE(Type::IsUint32(FormatMode::kUInt, 32)); + EXPECT_TRUE(Type::IsUint32(FormatMode::kUScaled, 32)); + EXPECT_FALSE(Type::IsUint32(FormatMode::kUFloat, 32)); + EXPECT_FALSE(Type::IsUint32(FormatMode::kSFloat, 32)); +} + +TEST_F(TypeTest, IsUint64) { + EXPECT_FALSE(Type::IsUint64(FormatMode::kSInt, 64)); + EXPECT_FALSE(Type::IsUint64(FormatMode::kSNorm, 64)); + EXPECT_FALSE(Type::IsUint64(FormatMode::kSScaled, 64)); + EXPECT_TRUE(Type::IsUint64(FormatMode::kSRGB, 64)); + EXPECT_TRUE(Type::IsUint64(FormatMode::kUNorm, 64)); + EXPECT_TRUE(Type::IsUint64(FormatMode::kUInt, 64)); + EXPECT_TRUE(Type::IsUint64(FormatMode::kUScaled, 64)); + EXPECT_FALSE(Type::IsUint64(FormatMode::kUFloat, 64)); + EXPECT_FALSE(Type::IsUint64(FormatMode::kSFloat, 64)); +} + +TEST_F(TypeTest, IsFloat16) { + EXPECT_TRUE(Type::IsFloat16(FormatMode::kSFloat, 16)); + EXPECT_TRUE(Type::IsFloat16(FormatMode::kUFloat, 16)); + EXPECT_FALSE(Type::IsFloat16(FormatMode::kSInt, 16)); + EXPECT_FALSE(Type::IsFloat16(FormatMode::kSNorm, 16)); + EXPECT_FALSE(Type::IsFloat16(FormatMode::kSScaled, 16)); + EXPECT_FALSE(Type::IsFloat16(FormatMode::kSRGB, 16)); + EXPECT_FALSE(Type::IsFloat16(FormatMode::kUNorm, 16)); + EXPECT_FALSE(Type::IsFloat16(FormatMode::kUInt, 16)); + EXPECT_FALSE(Type::IsFloat16(FormatMode::kUScaled, 16)); +} + +TEST_F(TypeTest, IsFloat32) { + EXPECT_TRUE(Type::IsFloat32(FormatMode::kSFloat, 32)); + EXPECT_TRUE(Type::IsFloat32(FormatMode::kUFloat, 32)); + EXPECT_FALSE(Type::IsFloat32(FormatMode::kSInt, 32)); + EXPECT_FALSE(Type::IsFloat32(FormatMode::kSNorm, 32)); + EXPECT_FALSE(Type::IsFloat32(FormatMode::kSScaled, 32)); + EXPECT_FALSE(Type::IsFloat32(FormatMode::kSRGB, 32)); + EXPECT_FALSE(Type::IsFloat32(FormatMode::kUNorm, 32)); + EXPECT_FALSE(Type::IsFloat32(FormatMode::kUInt, 32)); + EXPECT_FALSE(Type::IsFloat32(FormatMode::kUScaled, 32)); +} + +TEST_F(TypeTest, IsFloat64) { + EXPECT_TRUE(Type::IsFloat64(FormatMode::kSFloat, 64)); + EXPECT_TRUE(Type::IsFloat64(FormatMode::kUFloat, 64)); + EXPECT_FALSE(Type::IsFloat64(FormatMode::kSInt, 64)); + EXPECT_FALSE(Type::IsFloat64(FormatMode::kSNorm, 64)); + EXPECT_FALSE(Type::IsFloat64(FormatMode::kSScaled, 64)); + EXPECT_FALSE(Type::IsFloat64(FormatMode::kSRGB, 64)); + EXPECT_FALSE(Type::IsFloat64(FormatMode::kUNorm, 64)); + EXPECT_FALSE(Type::IsFloat64(FormatMode::kUInt, 64)); + EXPECT_FALSE(Type::IsFloat64(FormatMode::kUScaled, 64)); +} + +} // namespace type +} // namespace amber diff --git a/src/verifier.cc b/src/verifier.cc index cfa594f..ff4e288 100644 --- a/src/verifier.cc +++ b/src/verifier.cc @@ -34,7 +34,7 @@ const double kDefaultTexelTolerance = 0.002; void CopyBitsOfMemoryToBuffer(uint8_t* dst, const uint8_t* src, uint8_t src_bit_offset, - uint8_t bits) { + uint32_t bits) { while (src_bit_offset > static_cast<uint8_t>(7)) { ++src; src_bit_offset = static_cast<uint8_t>(src_bit_offset - kBitsPerByte); @@ -267,94 +267,60 @@ std::vector<double> GetActualValuesFromTexel(const uint8_t* texel, for (size_t i = 0; i < fmt->GetSegments().size(); ++i) { const auto& seg = fmt->GetSegments()[i]; - auto component = seg.GetComponent(); - if (seg.IsPadding()) { - bit_offset += component->num_bits; + bit_offset += seg.GetNumBits(); continue; } uint8_t actual[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - CopyBitsOfMemoryToBuffer(actual, texel, bit_offset, component->num_bits); - if (component->mode == FormatMode::kUFloat || - component->mode == FormatMode::kSFloat) { - if (component->num_bits < 32) { - actual_values[i] = - static_cast<double>(HexFloatToFloat(actual, component->num_bits)); - } else if (component->num_bits == 32) { - float* ptr = reinterpret_cast<float*>(actual); - actual_values[i] = static_cast<double>(*ptr); - } else if (component->num_bits == 64) { - double* ptr = reinterpret_cast<double*>(actual); - actual_values[i] = *ptr; - } else { - assert(false && "Bits of component is not for double nor float type"); - } + uint32_t num_bits = seg.GetNumBits(); + CopyBitsOfMemoryToBuffer(actual, texel, bit_offset, num_bits); + + FormatMode mode = seg.GetFormatMode(); + if (type::Type::IsInt8(mode, num_bits)) { + int8_t* ptr8 = nullptr; + ptr8 = reinterpret_cast<int8_t*>(actual); + actual_values[i] = static_cast<double>(*ptr8); + } else if (type::Type::IsInt16(mode, num_bits)) { + int16_t* ptr16 = nullptr; + ptr16 = reinterpret_cast<int16_t*>(actual); + actual_values[i] = static_cast<double>(*ptr16); + } else if (type::Type::IsInt32(mode, num_bits)) { + int32_t* ptr32 = nullptr; + ptr32 = reinterpret_cast<int32_t*>(actual); + actual_values[i] = static_cast<double>(*ptr32); + } else if (type::Type::IsInt64(mode, num_bits)) { + int64_t* ptr64 = nullptr; + ptr64 = reinterpret_cast<int64_t*>(actual); + actual_values[i] = static_cast<double>(*ptr64); + } else if (type::Type::IsUint8(mode, num_bits)) { + actual_values[i] = static_cast<double>(*actual); + } else if (type::Type::IsUint16(mode, num_bits)) { + uint16_t* ptr16 = nullptr; + ptr16 = reinterpret_cast<uint16_t*>(actual); + actual_values[i] = static_cast<double>(*ptr16); + } else if (type::Type::IsUint32(mode, num_bits)) { + uint32_t* ptr32 = nullptr; + ptr32 = reinterpret_cast<uint32_t*>(actual); + actual_values[i] = static_cast<double>(*ptr32); + } else if (type::Type::IsUint64(mode, num_bits)) { + uint64_t* ptr64 = nullptr; + ptr64 = reinterpret_cast<uint64_t*>(actual); + actual_values[i] = static_cast<double>(*ptr64); + } else if (type::Type::IsFloat32(mode, num_bits)) { + float* ptr = reinterpret_cast<float*>(actual); + actual_values[i] = static_cast<double>(*ptr); + } else if (type::Type::IsFloat64(mode, num_bits)) { + double* ptr = reinterpret_cast<double*>(actual); + actual_values[i] = *ptr; + } else if (type::Type::IsFloat(mode) && num_bits < 32) { + actual_values[i] = static_cast<double>( + HexFloatToFloat(actual, static_cast<uint8_t>(num_bits))); } else { - if (component->mode == FormatMode::kSInt || - component->mode == FormatMode::kSNorm) { - switch (component->num_bits) { - case 8: { - int8_t* ptr8 = nullptr; - ptr8 = reinterpret_cast<int8_t*>(actual); - actual_values[i] = static_cast<double>(*ptr8); - break; - } - case 16: { - int16_t* ptr16 = nullptr; - ptr16 = reinterpret_cast<int16_t*>(actual); - actual_values[i] = static_cast<double>(*ptr16); - break; - } - case 32: { - int32_t* ptr32 = nullptr; - ptr32 = reinterpret_cast<int32_t*>(actual); - actual_values[i] = static_cast<double>(*ptr32); - break; - } - case 64: { - int64_t* ptr64 = nullptr; - ptr64 = reinterpret_cast<int64_t*>(actual); - actual_values[i] = static_cast<double>(*ptr64); - break; - } - default: { - assert(false && "Bits of component is not for integer type"); - } - } - } else { - switch (component->num_bits) { - case 8: { - actual_values[i] = static_cast<double>(*actual); - break; - } - case 16: { - uint16_t* ptr16 = nullptr; - ptr16 = reinterpret_cast<uint16_t*>(actual); - actual_values[i] = static_cast<double>(*ptr16); - break; - } - case 32: { - uint32_t* ptr32 = nullptr; - ptr32 = reinterpret_cast<uint32_t*>(actual); - actual_values[i] = static_cast<double>(*ptr32); - break; - } - case 64: { - uint64_t* ptr64 = nullptr; - ptr64 = reinterpret_cast<uint64_t*>(actual); - actual_values[i] = static_cast<double>(*ptr64); - break; - } - default: { - assert(false && "Bits of component is not for integer type"); - } - } - } + assert(false && "Incorrect number of bits for number."); } - bit_offset += component->num_bits; + bit_offset += num_bits; } return actual_values; @@ -366,37 +332,24 @@ std::vector<double> GetActualValuesFromTexel(const uint8_t* texel, // ::kUFloat, ::kSFloat. void ScaleTexelValuesIfNeeded(std::vector<double>* texel, const Format* fmt) { assert(fmt->GetSegments().size() == texel->size()); + for (size_t i = 0; i < fmt->GetSegments().size(); ++i) { const auto& seg = fmt->GetSegments()[i]; if (seg.IsPadding()) continue; - auto component = seg.GetComponent(); - double scaled_value = (*texel)[i]; - switch (component->mode) { - case FormatMode::kUNorm: - scaled_value /= static_cast<double>((1 << component->num_bits) - 1); - break; - case FormatMode::kSNorm: - scaled_value /= - static_cast<double>((1 << (component->num_bits - 1)) - 1); - break; - case FormatMode::kUInt: - case FormatMode::kSInt: - case FormatMode::kUFloat: - case FormatMode::kSFloat: - break; - case FormatMode::kSRGB: - scaled_value /= static_cast<double>((1 << component->num_bits) - 1); - if (component->type != FormatComponentType::kA) - scaled_value = SRGBToLinearValue(scaled_value); - break; - case FormatMode::kUScaled: - case FormatMode::kSScaled: - assert(false && - "FormatMode::kUScaled and ::kSScaled are not implemented"); - break; + if (seg.GetFormatMode() == FormatMode::kUNorm) { + scaled_value /= static_cast<double>((1 << seg.GetNumBits()) - 1); + } else if (seg.GetFormatMode() == FormatMode::kSNorm) { + scaled_value /= static_cast<double>((1 << (seg.GetNumBits() - 1)) - 1); + } else if (seg.GetFormatMode() == FormatMode::kSRGB) { + scaled_value /= static_cast<double>((1 << seg.GetNumBits()) - 1); + if (seg.GetName() != FormatComponentType::kA) + scaled_value = SRGBToLinearValue(scaled_value); + } else if (seg.GetFormatMode() == FormatMode::kSScaled || + seg.GetFormatMode() == FormatMode::kUScaled) { + assert(false && "UScaled and SScaled are not implemented"); } (*texel)[i] = scaled_value; @@ -418,17 +371,15 @@ bool IsTexelEqualToExpected(const std::vector<double>& texel, if (seg.IsPadding()) continue; - auto component = seg.GetComponent(); - double texel_for_component = texel[i]; double expected = 0; double current_tolerance = 0; bool is_current_tolerance_percent = false; - switch (component->type) { + switch (seg.GetName()) { case FormatComponentType::kA: - if (!command->IsRGBA()) { + if (!command->IsRGBA()) continue; - } + expected = static_cast<double>(command->GetA()); current_tolerance = tolerance[3]; is_current_tolerance_percent = is_tolerance_percent[3]; @@ -469,8 +420,7 @@ std::vector<double> GetTexelInRGBA(const std::vector<double>& texel, if (seg.IsPadding()) continue; - auto component = seg.GetComponent(); - switch (component->type) { + switch (seg.GetName()) { case FormatComponentType::kR: texel_in_rgba[0] = texel[i]; break; @@ -560,7 +510,7 @@ Result Verifier::Probe(const ProbeCommand* command, uint32_t count_of_invalid_pixels = 0; uint32_t first_invalid_i = 0; uint32_t first_invalid_j = 0; - std::vector<double> actual_texel_values_on_failure; + std::vector<double> failure_values; for (uint32_t j = 0; j < height; ++j) { const uint8_t* p = ptr + row_stride * (j + y) + texel_stride * x; for (uint32_t i = 0; i < width; ++i) { @@ -570,8 +520,7 @@ Result Verifier::Probe(const ProbeCommand* command, if (!IsTexelEqualToExpected(actual_texel_values, fmt, command, tolerance, is_tolerance_percent)) { if (!count_of_invalid_pixels) { - actual_texel_values_on_failure = - GetTexelInRGBA(actual_texel_values, fmt); + failure_values = GetTexelInRGBA(actual_texel_values, fmt); first_invalid_i = i; first_invalid_j = j; } @@ -581,35 +530,34 @@ Result Verifier::Probe(const ProbeCommand* command, } if (count_of_invalid_pixels) { - float scale_factor_for_error_report = fmt->IsNormalized() ? 255.f : 1.f; - - return Result( + float scale = fmt->IsNormalized() ? 255.f : 1.f; + std::string reason = "Line " + std::to_string(command->GetLine()) + ": Probe failed at: " + std::to_string(x + first_invalid_i) + ", " + - std::to_string(first_invalid_j + y) + "\n" + " Expected RGBA: " + - std::to_string(command->GetR() * scale_factor_for_error_report) + ", " + - std::to_string(command->GetG() * scale_factor_for_error_report) + ", " + - std::to_string(command->GetB() * scale_factor_for_error_report) + - (command->IsRGBA() ? ", " + - std::to_string(command->GetA() * - scale_factor_for_error_report) + - "\n Actual RGBA: " - : "\n Actual RGB: ") + - std::to_string(static_cast<float>(actual_texel_values_on_failure[0]) * - scale_factor_for_error_report) + - ", " + - std::to_string(static_cast<float>(actual_texel_values_on_failure[1]) * - scale_factor_for_error_report) + - ", " + - std::to_string(static_cast<float>(actual_texel_values_on_failure[2]) * - scale_factor_for_error_report) + - (command->IsRGBA() - ? ", " + std::to_string(static_cast<float>( - actual_texel_values_on_failure[3]) * - scale_factor_for_error_report) - : "") + - "\n" + "Probe failed in " + std::to_string(count_of_invalid_pixels) + - " pixels"); + std::to_string(first_invalid_j + y) + "\n" + + " Expected: " + std::to_string(command->GetR() * scale) + ", " + + std::to_string(command->GetG() * scale) + ", " + + std::to_string(command->GetB() * scale); + + if (command->IsRGBA()) { + reason += ", " + std::to_string(command->GetA() * scale); + } + + reason += + "\n Actual: " + + std::to_string(static_cast<float>(failure_values[0]) * scale) + ", " + + std::to_string(static_cast<float>(failure_values[1]) * scale) + ", " + + std::to_string(static_cast<float>(failure_values[2]) * scale); + + if (command->IsRGBA()) { + reason += + ", " + std::to_string(static_cast<float>(failure_values[3]) * scale); + } + + reason += "\nProbe failed in " + std::to_string(count_of_invalid_pixels) + + " pixels"; + + return Result(reason); } return {}; @@ -658,7 +606,7 @@ Result Verifier::ProbeSSBO(const ProbeSSBOCommand* command, auto segment = segments[k]; // Skip over any padding bytes. while (segment.IsPadding()) { - ptr += segment.GetComponent()->SizeInBytes(); + ptr += segment.PaddingBytes(); ++k; if (k >= segments.size()) k = 0; @@ -667,25 +615,27 @@ Result Verifier::ProbeSSBO(const ProbeSSBOCommand* command, } Result r; - if (segment.GetComponent()->IsInt8()) + FormatMode mode = segment.GetFormatMode(); + uint32_t num_bits = segment.GetNumBits(); + if (type::Type::IsInt8(mode, num_bits)) r = CheckValue<int8_t>(command, ptr, value); - else if (segment.GetComponent()->IsUint8()) + else if (type::Type::IsUint8(mode, num_bits)) r = CheckValue<uint8_t>(command, ptr, value); - else if (segment.GetComponent()->IsInt16()) + else if (type::Type::IsInt16(mode, num_bits)) r = CheckValue<int16_t>(command, ptr, value); - else if (segment.GetComponent()->IsUint16()) + else if (type::Type::IsUint16(mode, num_bits)) r = CheckValue<uint16_t>(command, ptr, value); - else if (segment.GetComponent()->IsInt32()) + else if (type::Type::IsInt32(mode, num_bits)) r = CheckValue<int32_t>(command, ptr, value); - else if (segment.GetComponent()->IsUint32()) + else if (type::Type::IsUint32(mode, num_bits)) r = CheckValue<uint32_t>(command, ptr, value); - else if (segment.GetComponent()->IsInt64()) + else if (type::Type::IsInt64(mode, num_bits)) r = CheckValue<int64_t>(command, ptr, value); - else if (segment.GetComponent()->IsUint64()) + else if (type::Type::IsUint64(mode, num_bits)) r = CheckValue<uint64_t>(command, ptr, value); - else if (segment.GetComponent()->IsFloat()) + else if (type::Type::IsFloat32(mode, num_bits)) r = CheckValue<float>(command, ptr, value); - else if (segment.GetComponent()->IsDouble()) + else if (type::Type::IsFloat64(mode, num_bits)) r = CheckValue<double>(command, ptr, value); else return Result("Unknown datum type"); @@ -696,7 +646,7 @@ Result Verifier::ProbeSSBO(const ProbeSSBOCommand* command, std::to_string(i)); } - ptr += segment.GetComponent()->SizeInBytes(); + ptr += segment.SizeInBytes(); } return {}; diff --git a/src/verifier_test.cc b/src/verifier_test.cc index 3cbe86b..42e5aba 100644 --- a/src/verifier_test.cc +++ b/src/verifier_test.cc @@ -22,9 +22,9 @@ #include "amber/value.h" #include "gtest/gtest.h" #include "src/command.h" -#include "src/format_parser.h" #include "src/make_unique.h" #include "src/pipeline.h" +#include "src/type_parser.h" namespace amber { namespace { @@ -38,12 +38,15 @@ class VerifierTest : public testing::Test { if (color_frame_format_) return color_frame_format_.get(); - FormatParser fp; - color_frame_format_ = fp.Parse("B8G8R8A8_UNORM"); + TypeParser parser; + color_frame_type_ = parser.Parse("B8G8R8A8_UNORM"); + + color_frame_format_ = MakeUnique<Format>(color_frame_type_.get()); return color_frame_format_.get(); } private: + std::unique_ptr<type::Type> color_frame_type_; std::unique_ptr<Format> color_frame_format_; }; @@ -142,8 +145,8 @@ TEST_F(VerifierTest, ProbeFrameBufferRelativeSmallExpectFail) { Result r = verifier.Probe(&probe, GetColorFormat(), 4, 1000, 250, 250, static_cast<const void*>(frame_buffer)); EXPECT_EQ( - "Line 1: Probe failed at: 225, 225\n Expected RGBA: 25.500000, " - "0.000000, 0.000000, 0.000000\n Actual RGBA: 0.000000, 0.000000, " + "Line 1: Probe failed at: 225, 225\n Expected: 25.500000, " + "0.000000, 0.000000, 0.000000\n Actual: 0.000000, 0.000000, " "0.000000, 0.000000\nProbe failed in 625 pixels", r.Error()); } @@ -195,14 +198,15 @@ TEST_F(VerifierTest, ProbeFrameBufferUInt8) { uint8_t frame_buffer[4] = {255, 14, 75, 8}; - FormatParser fp; - auto fmt = fp.Parse("R8G8B8A8_UINT"); + TypeParser parser; + auto type = parser.Parse("R8G8B8A8_UINT"); + Format fmt(type.get()); Verifier verifier; - Result r = verifier.Probe(&probe, fmt.get(), - 4 * static_cast<uint32_t>(sizeof(uint8_t)), - 4 * static_cast<uint32_t>(sizeof(uint8_t)), 1, 1, - static_cast<const void*>(&frame_buffer)); + Result r = + verifier.Probe(&probe, &fmt, 4 * static_cast<uint32_t>(sizeof(uint8_t)), + 4 * static_cast<uint32_t>(sizeof(uint8_t)), 1, 1, + static_cast<const void*>(&frame_buffer)); EXPECT_TRUE(r.IsSuccess()); } @@ -221,14 +225,15 @@ TEST_F(VerifierTest, ProbeFrameBufferUInt16) { uint16_t frame_buffer[4] = {65535, 14, 1875, 8}; - FormatParser fp; - auto fmt = fp.Parse("R16G16B16A16_UINT"); + TypeParser parser; + auto type = parser.Parse("R16G16B16A16_UINT"); + Format fmt(type.get()); Verifier verifier; - Result r = verifier.Probe(&probe, fmt.get(), - 4 * static_cast<uint32_t>(sizeof(uint16_t)), - 4 * static_cast<uint32_t>(sizeof(uint16_t)), 1, 1, - static_cast<const void*>(&frame_buffer)); + Result r = + verifier.Probe(&probe, &fmt, 4 * static_cast<uint32_t>(sizeof(uint16_t)), + 4 * static_cast<uint32_t>(sizeof(uint16_t)), 1, 1, + static_cast<const void*>(&frame_buffer)); EXPECT_TRUE(r.IsSuccess()); } @@ -247,14 +252,15 @@ TEST_F(VerifierTest, ProbeFrameBufferUInt32) { uint32_t frame_buffer[4] = {6, 14, 1171875, 8}; - FormatParser fp; - auto fmt = fp.Parse("R32G32B32A32_UINT"); + TypeParser parser; + auto type = parser.Parse("R32G32B32A32_UINT"); + Format fmt(type.get()); Verifier verifier; - Result r = verifier.Probe(&probe, fmt.get(), - 4 * static_cast<uint32_t>(sizeof(uint32_t)), - 4 * static_cast<uint32_t>(sizeof(uint32_t)), 1, 1, - static_cast<const void*>(&frame_buffer)); + Result r = + verifier.Probe(&probe, &fmt, 4 * static_cast<uint32_t>(sizeof(uint32_t)), + 4 * static_cast<uint32_t>(sizeof(uint32_t)), 1, 1, + static_cast<const void*>(&frame_buffer)); EXPECT_TRUE(r.IsSuccess()); } @@ -273,14 +279,15 @@ TEST_F(VerifierTest, ProbeFrameBufferUInt64) { uint64_t frame_buffer[4] = {6, 14, 1171875, 8}; - FormatParser fp; - auto fmt = fp.Parse("R64G64B64A64_UINT"); + TypeParser parser; + auto type = parser.Parse("R64G64B64A64_UINT"); + Format fmt(type.get()); Verifier verifier; - Result r = verifier.Probe(&probe, fmt.get(), - 4 * static_cast<uint32_t>(sizeof(uint64_t)), - 4 * static_cast<uint32_t>(sizeof(uint64_t)), 1, 1, - static_cast<const void*>(&frame_buffer)); + Result r = + verifier.Probe(&probe, &fmt, 4 * static_cast<uint32_t>(sizeof(uint64_t)), + 4 * static_cast<uint32_t>(sizeof(uint64_t)), 1, 1, + static_cast<const void*>(&frame_buffer)); EXPECT_TRUE(r.IsSuccess()); } @@ -299,14 +306,15 @@ TEST_F(VerifierTest, ProbeFrameBufferSInt8) { int8_t frame_buffer[4] = {-6, 14, 75, 8}; - FormatParser fp; - auto fmt = fp.Parse("R8G8B8A8_SINT"); + TypeParser parser; + auto type = parser.Parse("R8G8B8A8_SINT"); + Format fmt(type.get()); Verifier verifier; - Result r = verifier.Probe(&probe, fmt.get(), - 4 * static_cast<uint32_t>(sizeof(int8_t)), - 4 * static_cast<uint32_t>(sizeof(int8_t)), 1, 1, - static_cast<const void*>(&frame_buffer)); + Result r = + verifier.Probe(&probe, &fmt, 4 * static_cast<uint32_t>(sizeof(int8_t)), + 4 * static_cast<uint32_t>(sizeof(int8_t)), 1, 1, + static_cast<const void*>(&frame_buffer)); EXPECT_TRUE(r.IsSuccess()); } @@ -325,14 +333,15 @@ TEST_F(VerifierTest, ProbeFrameBufferSInt16) { int16_t frame_buffer[4] = {-6, 14, 1875, 8}; - FormatParser fp; - auto fmt = fp.Parse("R16G16B16A16_SINT"); + TypeParser parser; + auto type = parser.Parse("R16G16B16A16_SINT"); + Format fmt(type.get()); Verifier verifier; - Result r = verifier.Probe(&probe, fmt.get(), - 4 * static_cast<uint32_t>(sizeof(int16_t)), - 4 * static_cast<uint32_t>(sizeof(int16_t)), 1, 1, - static_cast<const void*>(&frame_buffer)); + Result r = + verifier.Probe(&probe, &fmt, 4 * static_cast<uint32_t>(sizeof(int16_t)), + 4 * static_cast<uint32_t>(sizeof(int16_t)), 1, 1, + static_cast<const void*>(&frame_buffer)); EXPECT_TRUE(r.IsSuccess()); } @@ -351,14 +360,15 @@ TEST_F(VerifierTest, ProbeFrameBufferSInt32) { int32_t frame_buffer[4] = {-6, 14, 1171875, 8}; - FormatParser fp; - auto fmt = fp.Parse("R32G32B32A32_SINT"); + TypeParser parser; + auto type = parser.Parse("R32G32B32A32_SINT"); + Format fmt(type.get()); Verifier verifier; - Result r = verifier.Probe(&probe, fmt.get(), - 4 * static_cast<uint32_t>(sizeof(int32_t)), - 4 * static_cast<uint32_t>(sizeof(int32_t)), 1, 1, - static_cast<const void*>(&frame_buffer)); + Result r = + verifier.Probe(&probe, &fmt, 4 * static_cast<uint32_t>(sizeof(int32_t)), + 4 * static_cast<uint32_t>(sizeof(int32_t)), 1, 1, + static_cast<const void*>(&frame_buffer)); EXPECT_TRUE(r.IsSuccess()); } @@ -377,14 +387,15 @@ TEST_F(VerifierTest, ProbeFrameBufferSInt64) { int64_t frame_buffer[4] = {-6, 14, 1171875, 8}; - FormatParser fp; - auto fmt = fp.Parse("R64G64B64A64_SINT"); + TypeParser parser; + auto type = parser.Parse("R64G64B64A64_SINT"); + Format fmt(type.get()); Verifier verifier; - Result r = verifier.Probe(&probe, fmt.get(), - 4 * static_cast<uint32_t>(sizeof(int64_t)), - 4 * static_cast<uint32_t>(sizeof(int64_t)), 1, 1, - static_cast<const void*>(&frame_buffer)); + Result r = + verifier.Probe(&probe, &fmt, 4 * static_cast<uint32_t>(sizeof(int64_t)), + 4 * static_cast<uint32_t>(sizeof(int64_t)), 1, 1, + static_cast<const void*>(&frame_buffer)); EXPECT_TRUE(r.IsSuccess()); } @@ -403,14 +414,15 @@ TEST_F(VerifierTest, ProbeFrameBufferFloat32) { float frame_buffer[4] = {-6.0f, 14.0f, 0.1171875f, 0.8f}; - FormatParser fp; - auto fmt = fp.Parse("R32G32B32A32_SFLOAT"); + TypeParser parser; + auto type = parser.Parse("R32G32B32A32_SFLOAT"); + Format fmt(type.get()); Verifier verifier; - Result r = verifier.Probe(&probe, fmt.get(), - 4 * static_cast<uint32_t>(sizeof(float)), - 4 * static_cast<uint32_t>(sizeof(float)), 1, 1, - static_cast<const void*>(&frame_buffer)); + Result r = + verifier.Probe(&probe, &fmt, 4 * static_cast<uint32_t>(sizeof(float)), + 4 * static_cast<uint32_t>(sizeof(float)), 1, 1, + static_cast<const void*>(&frame_buffer)); EXPECT_TRUE(r.IsSuccess()); } @@ -429,14 +441,15 @@ TEST_F(VerifierTest, ProbeFrameBufferFloat64) { double frame_buffer[4] = {-6.0, 14.0, 0.1171875, 0.8}; - FormatParser fp; - auto fmt = fp.Parse("R64G64B64A64_SFLOAT"); + TypeParser parser; + auto type = parser.Parse("R64G64B64A64_SFLOAT"); + Format fmt(type.get()); Verifier verifier; - Result r = verifier.Probe(&probe, fmt.get(), - 4 * static_cast<uint32_t>(sizeof(double)), - 4 * static_cast<uint32_t>(sizeof(double)), 1, 1, - static_cast<const void*>(&frame_buffer)); + Result r = + verifier.Probe(&probe, &fmt, 4 * static_cast<uint32_t>(sizeof(double)), + 4 * static_cast<uint32_t>(sizeof(double)), 1, 1, + static_cast<const void*>(&frame_buffer)); EXPECT_TRUE(r.IsSuccess()); } @@ -469,11 +482,12 @@ TEST_F(VerifierTest, HexFloatToFloatR16G11B10) { frame_buffer |= 380ULL << (16ULL + 11ULL); probe.SetB(0.1171875f); - Format format; - format.SetFormatType(FormatType::kUnknown); - format.AddComponent(FormatComponentType::kR, FormatMode::kSFloat, 16); - format.AddComponent(FormatComponentType::kG, FormatMode::kUFloat, 11); - format.AddComponent(FormatComponentType::kB, FormatMode::kUFloat, 10); + auto list = MakeUnique<type::List>(); + list->AddMember(FormatComponentType::kR, FormatMode::kSFloat, 16); + list->AddMember(FormatComponentType::kG, FormatMode::kSFloat, 11); + list->AddMember(FormatComponentType::kB, FormatMode::kSFloat, 10); + + Format format(list.get()); Verifier verifier; Result r = verifier.Probe(&probe, &format, 6, 6, 1, 1, @@ -510,11 +524,12 @@ TEST_F(VerifierTest, HexFloatToFloatR11G16B10) { frame_buffer |= 380ULL << (16ULL + 11ULL); probe.SetB(0.1171875f); - Format format; - format.SetFormatType(FormatType::kUnknown); - format.AddComponent(FormatComponentType::kR, FormatMode::kSFloat, 11); - format.AddComponent(FormatComponentType::kG, FormatMode::kUFloat, 16); - format.AddComponent(FormatComponentType::kB, FormatMode::kUFloat, 10); + auto list = MakeUnique<type::List>(); + list->AddMember(FormatComponentType::kR, FormatMode::kSFloat, 11); + list->AddMember(FormatComponentType::kG, FormatMode::kSFloat, 16); + list->AddMember(FormatComponentType::kB, FormatMode::kSFloat, 10); + + Format format(list.get()); Verifier verifier; Result r = verifier.Probe(&probe, &format, 6, 6, 1, 1, @@ -551,11 +566,12 @@ TEST_F(VerifierTest, HexFloatToFloatR10G11B16) { frame_buffer |= 50688ULL << (10ULL + 11ULL); probe.SetB(-6.0f); - Format format; - format.SetFormatType(FormatType::kUnknown); - format.AddComponent(FormatComponentType::kR, FormatMode::kSFloat, 10); - format.AddComponent(FormatComponentType::kG, FormatMode::kUFloat, 11); - format.AddComponent(FormatComponentType::kB, FormatMode::kUFloat, 16); + auto list = MakeUnique<type::List>(); + list->AddMember(FormatComponentType::kR, FormatMode::kSFloat, 10); + list->AddMember(FormatComponentType::kG, FormatMode::kSFloat, 11); + list->AddMember(FormatComponentType::kB, FormatMode::kSFloat, 16); + + Format format(list.get()); Verifier verifier; Result r = verifier.Probe(&probe, &format, 6, 6, 1, 1, @@ -650,9 +666,11 @@ TEST_F(VerifierTest, ProbeSSBOUint8Single) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R8_UINT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R8_UINT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kEqual); std::vector<Value> values; @@ -674,10 +692,11 @@ TEST_F(VerifierTest, ProbeSSBOUint8Multiple) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R8_UINT"); + TypeParser parser; + auto type = parser.Parse("R8_UINT"); + Format fmt(type.get()); - probe_ssbo.SetFormat(fmt.get()); + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kEqual); std::vector<Value> values; @@ -700,10 +719,11 @@ TEST_F(VerifierTest, ProbeSSBOUint8Many) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R8_UINT"); + TypeParser parser; + auto type = parser.Parse("R8_UINT"); + Format fmt(type.get()); - probe_ssbo.SetFormat(fmt.get()); + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kEqual); std::vector<Value> values; @@ -730,9 +750,11 @@ TEST_F(VerifierTest, ProbeSSBOUint32Single) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R32_UINT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R32_UINT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kEqual); std::vector<Value> values; @@ -754,9 +776,11 @@ TEST_F(VerifierTest, ProbeSSBOUint32Multiple) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R32_UINT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R32_UINT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kEqual); std::vector<Value> values; @@ -780,9 +804,11 @@ TEST_F(VerifierTest, ProbeSSBOUint32Many) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R32_UINT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R32_UINT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kEqual); std::vector<Value> values; @@ -809,9 +835,11 @@ TEST_F(VerifierTest, ProbeSSBOFloatSingle) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R32_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R32_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kEqual); std::vector<Value> values; @@ -833,9 +861,11 @@ TEST_F(VerifierTest, ProbeSSBOFloatMultiple) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R32_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R32_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kEqual); std::vector<Value> values; @@ -859,9 +889,11 @@ TEST_F(VerifierTest, ProbeSSBOFloatMany) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R32_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R32_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kEqual); std::vector<Value> values; @@ -888,9 +920,11 @@ TEST_F(VerifierTest, ProbeSSBODoubleSingle) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kEqual); std::vector<Value> values; @@ -912,9 +946,11 @@ TEST_F(VerifierTest, ProbeSSBODoubleMultiple) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kEqual); std::vector<Value> values; @@ -938,9 +974,11 @@ TEST_F(VerifierTest, ProbeSSBODoubleMany) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kEqual); std::vector<Value> values; @@ -967,9 +1005,11 @@ TEST_F(VerifierTest, ProbeSSBOEqualFail) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kEqual); std::vector<Value> values; @@ -995,9 +1035,11 @@ TEST_F(VerifierTest, ProbeSSBOFuzzyEqualWithAbsoluteTolerance) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kFuzzyEqual); std::vector<Probe::Tolerance> tolerances; @@ -1030,9 +1072,11 @@ TEST_F(VerifierTest, ProbeSSBOFuzzyEqualWithAbsoluteToleranceFail) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kFuzzyEqual); std::vector<Probe::Tolerance> tolerances; @@ -1062,9 +1106,11 @@ TEST_F(VerifierTest, ProbeSSBOFuzzyEqualWithRelativeTolerance) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kFuzzyEqual); std::vector<Probe::Tolerance> tolerances; @@ -1097,9 +1143,11 @@ TEST_F(VerifierTest, ProbeSSBOFuzzyEqualWithRelativeToleranceFail) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kFuzzyEqual); std::vector<Probe::Tolerance> tolerances; @@ -1129,9 +1177,11 @@ TEST_F(VerifierTest, ProbeSSBONotEqual) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kNotEqual); std::vector<Value> values; @@ -1155,9 +1205,11 @@ TEST_F(VerifierTest, ProbeSSBONotEqualFail) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kNotEqual); std::vector<Value> values; @@ -1183,9 +1235,11 @@ TEST_F(VerifierTest, ProbeSSBOLess) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kLess); std::vector<Value> values; @@ -1209,9 +1263,11 @@ TEST_F(VerifierTest, ProbeSSBOLessFail) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kLess); std::vector<Value> values; @@ -1237,9 +1293,11 @@ TEST_F(VerifierTest, ProbeSSBOLessOrEqual) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kLessOrEqual); std::vector<Value> values; @@ -1263,9 +1321,11 @@ TEST_F(VerifierTest, ProbeSSBOLessOrEqualFail) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kLessOrEqual); std::vector<Value> values; @@ -1291,9 +1351,11 @@ TEST_F(VerifierTest, ProbeSSBOGreater) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kGreater); std::vector<Value> values; @@ -1317,9 +1379,11 @@ TEST_F(VerifierTest, ProbeSSBOGreaterFail) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kGreater); std::vector<Value> values; @@ -1345,9 +1409,11 @@ TEST_F(VerifierTest, ProbeSSBOGreaterOrEqual) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kGreaterOrEqual); std::vector<Value> values; @@ -1371,9 +1437,11 @@ TEST_F(VerifierTest, ProbeSSBOGreaterOrEqualFail) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("R64_SFLOAT"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("R64_SFLOAT"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kGreaterOrEqual); std::vector<Value> values; @@ -1415,8 +1483,8 @@ TEST_F(VerifierTest, CheckRGBAOrderForFailure) { static_cast<const void*>(&frame_buffer)); EXPECT_FALSE(r.IsSuccess()); EXPECT_EQ( - "Line 1: Probe failed at: 0, 0\n Expected RGBA: 153.000000, 102.000000, " - "0.000000, 76.500000\n Actual RGBA: 75.000000, 14.000000, 255.000000, " + "Line 1: Probe failed at: 0, 0\n Expected: 153.000000, 102.000000, " + "0.000000, 76.500000\n Actual: 75.000000, 14.000000, 255.000000, " "8.000000\nProbe failed in 1 pixels", r.Error()); } @@ -1427,9 +1495,11 @@ TEST_F(VerifierTest, ProbeSSBOWithPadding) { ProbeSSBOCommand probe_ssbo(color_buf.get()); - FormatParser fp; - auto fmt = fp.Parse("float/vec2"); - probe_ssbo.SetFormat(fmt.get()); + TypeParser parser; + auto type = parser.Parse("float/vec2"); + Format fmt(type.get()); + + probe_ssbo.SetFormat(&fmt); ASSERT_TRUE(probe_ssbo.GetFormat() != nullptr); probe_ssbo.SetComparator(ProbeSSBOCommand::Comparator::kLessOrEqual); diff --git a/src/vkscript/command_parser.cc b/src/vkscript/command_parser.cc index 5123991..dd4f918 100644 --- a/src/vkscript/command_parser.cc +++ b/src/vkscript/command_parser.cc @@ -22,9 +22,9 @@ #include <utility> #include "src/command_data.h" -#include "src/format_parser.h" #include "src/make_unique.h" #include "src/tokenizer.h" +#include "src/type_parser.h" #include "src/vkscript/datum_type_parser.h" namespace amber { @@ -491,7 +491,7 @@ Result CommandParser::ParseValues(const std::string& name, while (!token->IsEOL() && !token->IsEOS()) { Value v; - if ((fmt->IsFloat() || fmt->IsDouble())) { + if ((fmt->IsFloat32() || fmt->IsFloat64())) { if (!token->IsInteger() && !token->IsDouble()) { return Result(std::string("Invalid value provided to ") + name + " command: " + token->ToOriginalString()); @@ -520,7 +520,7 @@ Result CommandParser::ParseValues(const std::string& name, // This could overflow, but I don't really expect us to get command files // that big .... - size_t num_per_row = fmt->RowCount(); + size_t num_per_row = fmt->GetType()->RowCount(); if (seen == 0 || (seen % num_per_row) != 0) { return Result(std::string("Incorrect number of values provided to ") + name + " command"); @@ -589,14 +589,16 @@ Result CommandParser::ProcessSSBO() { token->ToOriginalString()); DatumTypeParser tp; - auto fmt = tp.Parse(token->AsString()); - if (!fmt) + auto type = tp.Parse(token->AsString()); + if (!type) return Result("Invalid type provided: " + token->AsString()); + auto fmt = MakeUnique<Format>(type.get()); auto* buf = cmd->GetBuffer(); if (buf->FormatIsDefault() || !buf->GetFormat()) { buf->SetFormat(fmt.get()); script_->RegisterFormat(std::move(fmt)); + script_->RegisterType(std::move(type)); } else if (!buf->GetFormat()->Equal(fmt.get())) { return Result("probe ssbo format does not match buffer format"); } @@ -641,10 +643,13 @@ Result CommandParser::ProcessSSBO() { // Set a default format into the buffer if needed. if (!buf->GetFormat()) { - FormatParser fp; - auto fmt = fp.Parse("R8_SINT"); + TypeParser parser; + auto type = parser.Parse("R8_SINT"); + auto fmt = MakeUnique<Format>(type.get()); buf->SetFormat(fmt.get()); script_->RegisterFormat(std::move(fmt)); + script_->RegisterType(std::move(type)); + // This has to come after the SetFormat() call because SetFormat() resets // the value back to false. buf->SetFormatIsDefault(true); @@ -740,10 +745,12 @@ Result CommandParser::ProcessUniform() { } DatumTypeParser tp; - auto fmt = tp.Parse(token->AsString()); - if (!fmt) + auto type = tp.Parse(token->AsString()); + if (!type) return Result("Invalid type provided: " + token->AsString()); + auto fmt = MakeUnique<Format>(type.get()); + // uniform is always std140. if (is_ubo) fmt->SetLayout(Format::Layout::kStd140); @@ -752,6 +759,7 @@ Result CommandParser::ProcessUniform() { if (buf->FormatIsDefault() || !buf->GetFormat()) { buf->SetFormat(fmt.get()); script_->RegisterFormat(std::move(fmt)); + script_->RegisterType(std::move(type)); } else if (!buf->GetFormat()->Equal(fmt.get())) { return Result("probe ssbo format does not match buffer format"); } @@ -2018,8 +2026,8 @@ Result CommandParser::ProcessProbeSSBO() { token->ToOriginalString()); DatumTypeParser tp; - auto fmt = tp.Parse(token->AsString()); - if (!fmt) + auto type = tp.Parse(token->AsString()); + if (!type) return Result("Invalid type provided: " + token->AsString()); token = tokenizer_->NextToken(); @@ -2061,6 +2069,7 @@ Result CommandParser::ProcessProbeSSBO() { std::to_string(binding)); } + auto fmt = MakeUnique<Format>(type.get()); if (buffer->FormatIsDefault() || !buffer->GetFormat()) { buffer->SetFormat(fmt.get()); } else if (buffer->GetFormat() && !buffer->GetFormat()->Equal(fmt.get())) { @@ -2075,6 +2084,7 @@ Result CommandParser::ProcessProbeSSBO() { cmd->SetBinding(binding); script_->RegisterFormat(std::move(fmt)); + script_->RegisterType(std::move(type)); if (!token->IsInteger()) return Result("Invalid offset for probe ssbo command: " + diff --git a/src/vkscript/command_parser_test.cc b/src/vkscript/command_parser_test.cc index 1efba07..f88006c 100644 --- a/src/vkscript/command_parser_test.cc +++ b/src/vkscript/command_parser_test.cc @@ -3074,6 +3074,7 @@ TEST_F(CommandParserTest, SSBOSubdataWithFloat) { Pipeline pipeline(PipelineType::kGraphics); Script script; + CommandParser cp(&script, &pipeline, 1, data); Result r = cp.Parse(); ASSERT_TRUE(r.IsSuccess()) << r.Error(); @@ -3090,9 +3091,12 @@ TEST_F(CommandParserTest, SSBOSubdataWithFloat) { ASSERT_TRUE(cmd->IsSubdata()); auto* fmt = cmd->GetBuffer()->GetFormat(); - EXPECT_TRUE(fmt->IsFloat()); - EXPECT_EQ(1U, fmt->ColumnCount()); - EXPECT_EQ(3U, fmt->RowCount()); + ASSERT_TRUE(fmt->GetType()->IsNumber()); + + auto n = fmt->GetType()->AsNumber(); + EXPECT_TRUE(type::Type::IsFloat32(n->GetFormatMode(), n->NumBits())); + EXPECT_EQ(1U, fmt->GetType()->ColumnCount()); + EXPECT_EQ(3U, fmt->GetType()->RowCount()); const auto& values = cmd->GetValues(); std::vector<float> results = {2.3f, 4.2f, 1.2f}; @@ -3134,9 +3138,12 @@ TEST_F(CommandParserTest, SSBOSubdataWithDescriptorSet) { EXPECT_EQ(16U, cmd->GetOffset()); auto* fmt = cmd->GetBuffer()->GetFormat(); - EXPECT_TRUE(fmt->IsFloat()); - EXPECT_EQ(1U, fmt->ColumnCount()); - EXPECT_EQ(3U, fmt->RowCount()); + ASSERT_TRUE(fmt->GetType()->IsNumber()); + + auto n = fmt->GetType()->AsNumber(); + EXPECT_TRUE(type::Type::IsFloat32(n->GetFormatMode(), n->NumBits())); + EXPECT_EQ(1U, fmt->GetType()->ColumnCount()); + EXPECT_EQ(3U, fmt->GetType()->RowCount()); const auto& values = cmd->GetValues(); std::vector<float> results = {2.3f, 4.2f, 1.2f}; @@ -3167,9 +3174,12 @@ TEST_F(CommandParserTest, SSBOSubdataWithInts) { EXPECT_EQ(8U, cmd->GetOffset()); auto* fmt = cmd->GetBuffer()->GetFormat(); - EXPECT_TRUE(fmt->IsInt16()); - EXPECT_EQ(1U, fmt->ColumnCount()); - EXPECT_EQ(3U, fmt->RowCount()); + ASSERT_TRUE(fmt->GetType()->IsNumber()); + + auto n = fmt->GetType()->AsNumber(); + EXPECT_TRUE(type::Type::IsInt16(n->GetFormatMode(), n->NumBits())); + EXPECT_EQ(1U, fmt->GetType()->ColumnCount()); + EXPECT_EQ(3U, fmt->GetType()->RowCount()); const auto& values = cmd->GetValues(); std::vector<int16_t> results = {2, 4, 1}; @@ -3200,9 +3210,12 @@ TEST_F(CommandParserTest, SSBOSubdataWithMultipleVectors) { EXPECT_EQ(8U, cmd->GetOffset()); auto* fmt = cmd->GetBuffer()->GetFormat(); - EXPECT_TRUE(fmt->IsInt16()); - EXPECT_EQ(1U, fmt->ColumnCount()); - EXPECT_EQ(3U, fmt->RowCount()); + ASSERT_TRUE(fmt->GetType()->IsNumber()); + + auto n = fmt->GetType()->AsNumber(); + EXPECT_TRUE(type::Type::IsInt16(n->GetFormatMode(), n->NumBits())); + EXPECT_EQ(1U, fmt->GetType()->ColumnCount()); + EXPECT_EQ(3U, fmt->GetType()->RowCount()); const auto& values = cmd->GetValues(); std::vector<int16_t> results = {2, 4, 1, 3, 6, 8}; @@ -3332,14 +3345,16 @@ TEST_F(CommandParserTest, Uniform) { EXPECT_EQ(32U, cmd->GetOffset()); auto* fmt = cmd->GetBuffer()->GetFormat(); - EXPECT_TRUE(fmt->IsFloat()); - EXPECT_EQ(1U, fmt->ColumnCount()); - EXPECT_EQ(3U, fmt->RowCount()); + ASSERT_TRUE(fmt->GetType()->IsNumber()); + + auto n = fmt->GetType()->AsNumber(); + EXPECT_TRUE(type::Type::IsFloat32(n->GetFormatMode(), n->NumBits())); + EXPECT_EQ(1U, fmt->GetType()->ColumnCount()); + EXPECT_EQ(3U, fmt->GetType()->RowCount()); const auto* buf = cmd->GetBuffer(); const auto* values = buf->GetValues<float>(); std::vector<float> results = {2.1f, 3.2f, 4.3f, 0.f}; - ASSERT_EQ(results.size(), buf->ValueCount()); for (size_t i = 0; i < results.size(); ++i) { EXPECT_FLOAT_EQ(results[i], values[i]); } @@ -3374,14 +3389,16 @@ TEST_F(CommandParserTest, UniformWithContinuation) { EXPECT_EQ(16U, cmd->GetOffset()); auto* fmt = cmd->GetBuffer()->GetFormat(); - EXPECT_TRUE(fmt->IsFloat()); - EXPECT_EQ(1U, fmt->ColumnCount()); - EXPECT_EQ(3U, fmt->RowCount()); + ASSERT_TRUE(fmt->GetType()->IsNumber()); + + auto n = fmt->GetType()->AsNumber(); + EXPECT_TRUE(type::Type::IsFloat32(n->GetFormatMode(), n->NumBits())); + EXPECT_EQ(1U, fmt->GetType()->ColumnCount()); + EXPECT_EQ(3U, fmt->GetType()->RowCount()); const auto* buf = cmd->GetBuffer(); const auto* values = buf->GetValues<float>(); std::vector<float> results = {2.1f, 3.2f, 4.3f, 0.f, 5.4f, 6.7f, 8.9f, 0.f}; - ASSERT_EQ(results.size(), buf->ValueCount()); for (size_t i = 0; i < results.size(); ++i) { EXPECT_FLOAT_EQ(results[i], values[i]); } @@ -3452,9 +3469,12 @@ TEST_F(CommandParserTest, UniformUBO) { EXPECT_EQ(static_cast<uint32_t>(0), cmd->GetOffset()); auto* fmt = cmd->GetBuffer()->GetFormat(); - EXPECT_TRUE(fmt->IsFloat()); - EXPECT_EQ(1U, fmt->ColumnCount()); - EXPECT_EQ(3U, fmt->RowCount()); + ASSERT_TRUE(fmt->GetType()->IsNumber()); + + auto n = fmt->GetType()->AsNumber(); + EXPECT_TRUE(type::Type::IsFloat32(n->GetFormatMode(), n->NumBits())); + EXPECT_EQ(1U, fmt->GetType()->ColumnCount()); + EXPECT_EQ(3U, fmt->GetType()->RowCount()); const auto& values = cmd->GetValues(); std::vector<float> results = {2.1f, 3.2f, 4.3f}; @@ -3507,9 +3527,12 @@ TEST_F(CommandParserTest, UniformUBOWithDescriptorSet) { EXPECT_EQ(16U, cmd->GetOffset()); auto* fmt = cmd->GetBuffer()->GetFormat(); - EXPECT_TRUE(fmt->IsFloat()); - EXPECT_EQ(1U, fmt->ColumnCount()); - EXPECT_EQ(3U, fmt->RowCount()); + ASSERT_TRUE(fmt->GetType()->IsNumber()); + + auto n = fmt->GetType()->AsNumber(); + EXPECT_TRUE(type::Type::IsFloat32(n->GetFormatMode(), n->NumBits())); + EXPECT_EQ(1U, fmt->GetType()->ColumnCount()); + EXPECT_EQ(3U, fmt->GetType()->RowCount()); const auto& values = cmd->GetValues(); std::vector<float> results = {2.1f, 3.2f, 4.3f}; @@ -3925,9 +3948,12 @@ probe ssbo vec3 3:6 2 >= 2.3 4.2 1.2)"; cmd->GetComparator()); auto* fmt = cmd->GetFormat(); - EXPECT_TRUE(fmt->IsFloat()); - EXPECT_EQ(1U, fmt->ColumnCount()); - EXPECT_EQ(3U, fmt->RowCount()); + ASSERT_TRUE(fmt->GetType()->IsNumber()); + + auto n = fmt->GetType()->AsNumber(); + EXPECT_TRUE(type::Type::IsFloat32(n->GetFormatMode(), n->NumBits())); + EXPECT_EQ(1U, fmt->GetType()->ColumnCount()); + EXPECT_EQ(3U, fmt->GetType()->RowCount()); const auto& values = cmd->GetValues(); std::vector<float> results = {2.3f, 4.2f, 1.2f}; @@ -3960,9 +3986,12 @@ probe ssbo vec3 6 2 >= 2.3 4.2 1.2)"; cmd->GetComparator()); auto* fmt = cmd->GetFormat(); - EXPECT_TRUE(fmt->IsFloat()); - EXPECT_EQ(1U, fmt->ColumnCount()); - EXPECT_EQ(3U, fmt->RowCount()); + ASSERT_TRUE(fmt->GetType()->IsNumber()); + + auto n = fmt->GetType()->AsNumber(); + EXPECT_TRUE(type::Type::IsFloat32(n->GetFormatMode(), n->NumBits())); + EXPECT_EQ(1U, fmt->GetType()->ColumnCount()); + EXPECT_EQ(3U, fmt->GetType()->RowCount()); const auto& values = cmd->GetValues(); std::vector<float> results = {2.3f, 4.2f, 1.2f}; @@ -3995,9 +4024,12 @@ probe ssbo vec3 6 2 >= 2.3 4.2 1.2)"; cmd->GetComparator()); auto* fmt = cmd->GetFormat(); - EXPECT_TRUE(fmt->IsFloat()); - EXPECT_EQ(1U, fmt->ColumnCount()); - EXPECT_EQ(3U, fmt->RowCount()); + ASSERT_TRUE(fmt->GetType()->IsNumber()); + + auto n = fmt->GetType()->AsNumber(); + EXPECT_TRUE(type::Type::IsFloat32(n->GetFormatMode(), n->NumBits())); + EXPECT_EQ(1U, fmt->GetType()->ColumnCount()); + EXPECT_EQ(3U, fmt->GetType()->RowCount()); const auto& values = cmd->GetValues(); std::vector<float> results = {2.3f, 4.2f, 1.2f}; @@ -4029,9 +4061,12 @@ probe ssbo i16vec3 6 2 <= 2 4 1)"; EXPECT_EQ(ProbeSSBOCommand::Comparator::kLessOrEqual, cmd->GetComparator()); auto* fmt = cmd->GetFormat(); - EXPECT_TRUE(fmt->IsInt16()); - EXPECT_EQ(1U, fmt->ColumnCount()); - EXPECT_EQ(3U, fmt->RowCount()); + ASSERT_TRUE(fmt->GetType()->IsNumber()); + + auto n = fmt->GetType()->AsNumber(); + EXPECT_TRUE(type::Type::IsInt16(n->GetFormatMode(), n->NumBits())); + EXPECT_EQ(1U, fmt->GetType()->ColumnCount()); + EXPECT_EQ(3U, fmt->GetType()->RowCount()); const auto& values = cmd->GetValues(); std::vector<int16_t> results = {2, 4, 1}; @@ -4063,9 +4098,12 @@ probe ssbo i16vec3 6 2 == 2 4 1 3 6 8)"; EXPECT_EQ(ProbeSSBOCommand::Comparator::kEqual, cmd->GetComparator()); auto* fmt = cmd->GetFormat(); - EXPECT_TRUE(fmt->IsInt16()); - EXPECT_EQ(1U, fmt->ColumnCount()); - EXPECT_EQ(3U, fmt->RowCount()); + ASSERT_TRUE(fmt->GetType()->IsNumber()); + + auto n = fmt->GetType()->AsNumber(); + EXPECT_TRUE(type::Type::IsInt16(n->GetFormatMode(), n->NumBits())); + EXPECT_EQ(1U, fmt->GetType()->ColumnCount()); + EXPECT_EQ(3U, fmt->GetType()->RowCount()); const auto& values = cmd->GetValues(); std::vector<int16_t> results = {2, 4, 1, 3, 6, 8}; diff --git a/src/vkscript/datum_type_parser.cc b/src/vkscript/datum_type_parser.cc index 2a9dcaf..9062960 100644 --- a/src/vkscript/datum_type_parser.cc +++ b/src/vkscript/datum_type_parser.cc @@ -14,114 +14,90 @@ #include "src/vkscript/datum_type_parser.h" -#include "src/format_parser.h" #include "src/make_unique.h" +#include "src/type_parser.h" namespace amber { namespace vkscript { -namespace { - -FormatComponentType FORMAT_TYPES[] = { - FormatComponentType::kR, FormatComponentType::kG, FormatComponentType::kB, - FormatComponentType::kA}; - -} // namespace DatumTypeParser::DatumTypeParser() = default; DatumTypeParser::~DatumTypeParser() = default; -std::unique_ptr<Format> DatumTypeParser::Parse(const std::string& data) { - std::unique_ptr<Format> fmt; - - FormatParser fp; - bool matrix = false; - if (data == "int") { - fmt = fp.Parse("R32_SINT"); - } else if (data == "uint") { - fmt = fp.Parse("R32_UINT"); - } else if (data == "int8_t") { - fmt = fp.Parse("R8_SINT"); - } else if (data == "uint8_t") { - fmt = fp.Parse("R8_UINT"); - } else if (data == "int16_t") { - fmt = fp.Parse("R16_SINT"); - } else if (data == "uint16_t") { - fmt = fp.Parse("R16_UINT"); - } else if (data == "int64_t") { - fmt = fp.Parse("R64_SINT"); - } else if (data == "uint64_t") { - fmt = fp.Parse("R64_UINT"); - } else if (data == "float") { - fmt = fp.Parse("R32_SFLOAT"); - } else if (data == "double") { - fmt = fp.Parse("R64_SFLOAT"); - } else { - fmt = MakeUnique<Format>(); - int row_count = 4; - FormatMode mode = FormatMode::kSFloat; - uint8_t num_bits = 32; - - size_t vec_pos = data.find("vec"); - if (vec_pos != std::string::npos) { - if (data[0] == 'i') { - mode = FormatMode::kSInt; - } else if (data[0] == 'u') { - mode = FormatMode::kUInt; - } else if (data[0] == 'd') { - num_bits = 64; - } - - if (data[1] == '8') - num_bits = 8; - else if (data[1] == '1' && data[2] == '6') - num_bits = 16; - else if (data[1] == '6' && data[2] == '4') - num_bits = 64; - - if ((vec_pos + 3) < data.length()) - row_count = data[vec_pos + 3] - '0'; - - } else { - size_t mat_pos = data.find("mat"); - if (mat_pos == std::string::npos) - return nullptr; - - matrix = true; +std::unique_ptr<type::Type> DatumTypeParser::Parse(const std::string& data) { + TypeParser tp; + if (data == "int") + return tp.Parse("R32_SINT"); + if (data == "uint") + return tp.Parse("R32_UINT"); + if (data == "int8_t") + return tp.Parse("R8_SINT"); + if (data == "uint8_t") + return tp.Parse("R8_UINT"); + if (data == "int16_t") + return tp.Parse("R16_SINT"); + if (data == "uint16_t") + return tp.Parse("R16_UINT"); + if (data == "int64_t") + return tp.Parse("R64_SINT"); + if (data == "uint64_t") + return tp.Parse("R64_UINT"); + if (data == "float") + return tp.Parse("R32_SFLOAT"); + if (data == "double") + return tp.Parse("R64_SFLOAT"); + + int row_count = 4; + int column_count = 1; + FormatMode mode = FormatMode::kSFloat; + uint8_t num_bits = 32; + size_t vec_pos = data.find("vec"); + if (vec_pos != std::string::npos) { + if (data[0] == 'i') { + mode = FormatMode::kSInt; + } else if (data[0] == 'u') { + mode = FormatMode::kUInt; + } else if (data[0] == 'd') { + num_bits = 64; + } - if (data[0] == 'd') - num_bits = 64; + if (data[1] == '8') + num_bits = 8; + else if (data[1] == '1' && data[2] == '6') + num_bits = 16; + else if (data[1] == '6' && data[2] == '4') + num_bits = 64; - int column_count = 1; - if (mat_pos + 3 < data.length()) - column_count = data[mat_pos + 3] - '0'; + if ((vec_pos + 3) < data.length()) + row_count = data[vec_pos + 3] - '0'; + } else { + size_t mat_pos = data.find("mat"); + if (mat_pos == std::string::npos) + return nullptr; - if (mat_pos + 5 < data.length()) - row_count = data[mat_pos + 5] - '0'; - else - row_count = column_count; + if (data[0] == 'd') + num_bits = 64; - fmt->SetColumnCount(static_cast<uint32_t>(column_count)); - } + if (mat_pos + 3 < data.length()) + column_count = data[mat_pos + 3] - '0'; - for (int i = 0; i < row_count; ++i) - fmt->AddComponent(FORMAT_TYPES[i], mode, num_bits); + if (mat_pos + 5 < data.length()) + row_count = data[mat_pos + 5] - '0'; + else + row_count = column_count; } - if (!fmt) - return nullptr; - - // Convert the name back into a FormatType so we can use it in the buffer - // later Otherwise, we end up with a type of Unknown. - // - // There is no equivalent type for a matrix. - if (!matrix) { - std::string name = fmt->GenerateName(); - if (name == "") - return nullptr; - fmt->SetFormatType(FormatParser::NameToType(name)); - } - return fmt; + std::unique_ptr<type::Type> type; + if (mode == FormatMode::kSFloat) + type = type::Number::Float(num_bits); + else if (mode == FormatMode::kSInt) + type = type::Number::Int(num_bits); + else + type = type::Number::Uint(num_bits); + + type->SetRowCount(static_cast<uint32_t>(row_count)); + type->SetColumnCount(static_cast<uint32_t>(column_count)); + return type; } } // namespace vkscript diff --git a/src/vkscript/datum_type_parser.h b/src/vkscript/datum_type_parser.h index 9d37228..ca01122 100644 --- a/src/vkscript/datum_type_parser.h +++ b/src/vkscript/datum_type_parser.h @@ -19,7 +19,7 @@ #include <string> #include "amber/result.h" -#include "src/format.h" +#include "src/type.h" namespace amber { namespace vkscript { @@ -30,7 +30,7 @@ class DatumTypeParser { DatumTypeParser(); ~DatumTypeParser(); - std::unique_ptr<Format> Parse(const std::string& data); + std::unique_ptr<type::Type> Parse(const std::string& data); }; } // namespace vkscript diff --git a/src/vkscript/datum_type_parser_test.cc b/src/vkscript/datum_type_parser_test.cc index 23d9eb3..a9d6089 100644 --- a/src/vkscript/datum_type_parser_test.cc +++ b/src/vkscript/datum_type_parser_test.cc @@ -15,6 +15,7 @@ #include "src/vkscript/datum_type_parser.h" #include "gtest/gtest.h" +#include "src/format.h" namespace amber { namespace vkscript { @@ -24,10 +25,10 @@ bool AllCompsAreType(Format* fmt, FormatMode mode, uint8_t num_bits) { for (auto& seg : fmt->GetSegments()) { if (seg.IsPadding()) continue; - if (seg.GetComponent()->mode != mode || - seg.GetComponent()->num_bits != num_bits) { + if (seg.GetNumBits() != num_bits) + return false; + if (seg.GetFormatMode() != mode) return false; - } } return true; @@ -39,14 +40,14 @@ using DatumTypeParserTest = testing::Test; TEST_F(DatumTypeParserTest, EmptyType) { DatumTypeParser tp; - auto fmt = tp.Parse(""); - ASSERT_TRUE(fmt == nullptr); + auto type = tp.Parse(""); + ASSERT_TRUE(type == nullptr); } TEST_F(DatumTypeParserTest, InvalidType) { DatumTypeParser tp; - auto fmt = tp.Parse("INVALID"); - ASSERT_TRUE(fmt == nullptr); + auto type = tp.Parse("INVALID"); + ASSERT_TRUE(type == nullptr); } struct DatumTypeData { @@ -63,12 +64,13 @@ TEST_P(DatumTypeDataTest, Parser) { const auto& test_data = GetParam(); DatumTypeParser tp; - auto fmt = tp.Parse(test_data.name); + auto type = tp.Parse(test_data.name); - ASSERT_TRUE(fmt != nullptr); - EXPECT_TRUE(AllCompsAreType(fmt.get(), test_data.type, test_data.num_bits)); - EXPECT_EQ(test_data.column_count, fmt->ColumnCount()); - EXPECT_EQ(test_data.row_count, fmt->RowCount()); + ASSERT_TRUE(type != nullptr); + Format fmt(type.get()); + EXPECT_TRUE(AllCompsAreType(&fmt, test_data.type, test_data.num_bits)); + EXPECT_EQ(test_data.column_count, type->ColumnCount()); + EXPECT_EQ(test_data.row_count, type->RowCount()); } INSTANTIATE_TEST_SUITE_P( @@ -155,10 +157,12 @@ TEST_P(DatumTypeTestFormat, ToFormat) { auto test_data = GetParam(); DatumTypeParser tp; - auto fmt = tp.Parse(test_data.name); + auto type = tp.Parse(test_data.name); + + ASSERT_TRUE(type != nullptr) << test_data.name; - ASSERT_TRUE(fmt != nullptr); - ASSERT_EQ(test_data.format_type, fmt->GetFormatType()); + Format fmt(type.get()); + ASSERT_EQ(test_data.format_type, fmt.GetFormatType()) << test_data.name; } INSTANTIATE_TEST_SUITE_P( diff --git a/src/vkscript/parser.cc b/src/vkscript/parser.cc index 6ae7684..12e94fb 100644 --- a/src/vkscript/parser.cc +++ b/src/vkscript/parser.cc @@ -21,9 +21,9 @@ #include <utility> #include <vector> -#include "src/format_parser.h" #include "src/make_unique.h" #include "src/shader.h" +#include "src/type_parser.h" #include "src/vkscript/command_parser.h" namespace amber { @@ -169,26 +169,29 @@ Result Parser::ProcessRequireBlock(const SectionParser::Section& section) { if (!token->IsString()) return Result(make_error(tokenizer, "Missing framebuffer format")); - FormatParser fmt_parser; - auto fmt = fmt_parser.Parse(token->AsString()); - if (fmt == nullptr) { + TypeParser type_parser; + auto type = type_parser.Parse(token->AsString()); + if (type == nullptr) { return Result( make_error(tokenizer, "Failed to parse framebuffer format: " + token->ToOriginalString())); } + + auto fmt = MakeUnique<Format>(type.get()); script_->GetPipeline(kDefaultPipelineName) ->GetColorAttachments()[0] .buffer->SetFormat(fmt.get()); script_->RegisterFormat(std::move(fmt)); + script_->RegisterType(std::move(type)); } else if (str == "depthstencil") { token = tokenizer.NextToken(); if (!token->IsString()) return Result(make_error(tokenizer, "Missing depthStencil format")); - FormatParser fmt_parser; - auto fmt = fmt_parser.Parse(token->AsString()); - if (fmt == nullptr) { + TypeParser type_parser; + auto type = type_parser.Parse(token->AsString()); + if (type == nullptr) { return Result( make_error(tokenizer, "Failed to parse depthstencil format: " + token->ToOriginalString())); @@ -198,10 +201,12 @@ Result Parser::ProcessRequireBlock(const SectionParser::Section& section) { if (pipeline->GetDepthBuffer().buffer != nullptr) return Result("Only one depthstencil command allowed"); + auto fmt = MakeUnique<Format>(type.get()); // Generate and add a depth buffer auto depth_buf = pipeline->GenerateDefaultDepthAttachmentBuffer(); depth_buf->SetFormat(fmt.get()); script_->RegisterFormat(std::move(fmt)); + script_->RegisterType(std::move(type)); Result r = pipeline->SetDepthBuffer(depth_buf.get()); if (!r.IsSuccess()) @@ -290,14 +295,16 @@ Result Parser::ProcessIndicesBlock(const SectionParser::Section& section) { } if (!indices.empty()) { - FormatParser fp; - auto fmt = fp.Parse("R32_UINT"); + TypeParser parser; + auto type = parser.Parse("R32_UINT"); + auto fmt = MakeUnique<Format>(type.get()); auto b = MakeUnique<Buffer>(BufferType::kIndex); auto* buf = b.get(); b->SetName("indices"); b->SetFormat(fmt.get()); b->SetData(std::move(indices)); script_->RegisterFormat(std::move(fmt)); + script_->RegisterType(std::move(type)); Result r = script_->AddBuffer(std::move(b)); if (!r.IsSuccess()) @@ -325,7 +332,7 @@ Result Parser::ProcessVertexDataBlock(const SectionParser::Section& section) { // Process the header line. struct Header { uint8_t location; - std::unique_ptr<Format> format; + Format* format; }; std::vector<Header> headers; while (!token->IsEOL() && !token->IsEOS()) { @@ -351,15 +358,18 @@ Result Parser::ProcessVertexDataBlock(const SectionParser::Section& section) { return Result(make_error(tokenizer, "Vertex data format too short: " + token->ToOriginalString())); - FormatParser parser; - auto fmt = parser.Parse(fmt_name.substr(1, fmt_name.length())); - if (!fmt) { + TypeParser parser; + auto type = parser.Parse(fmt_name.substr(1, fmt_name.length())); + if (!type) { return Result( make_error(tokenizer, "Invalid format in vertex data header: " + fmt_name.substr(1, fmt_name.length()))); } - headers.push_back({loc, std::move(fmt)}); + auto fmt = MakeUnique<Format>(type.get()); + headers.push_back({loc, fmt.get()}); + script_->RegisterFormat(std::move(fmt)); + script_->RegisterType(std::move(type)); token = tokenizer.NextToken(); } @@ -377,7 +387,8 @@ Result Parser::ProcessVertexDataBlock(const SectionParser::Section& section) { const auto& header = headers[j]; auto& value_data = values[j]; - if (header.format->GetPackSize() > 0) { + auto* type = header.format->GetType(); + if (type->IsList() && type->AsList()->IsPacked()) { if (!token->IsHex()) { return Result( make_error(tokenizer, "Invalid packed value in Vertex Data: " + @@ -398,11 +409,9 @@ Result Parser::ProcessVertexDataBlock(const SectionParser::Section& section) { "Too few cells in given vertex data row")); } - auto comp = seg.GetComponent(); - Value v; - if (comp->mode == FormatMode::kUFloat || - comp->mode == FormatMode::kSFloat) { + if (seg.GetFormatMode() == FormatMode::kUFloat || + seg.GetFormatMode() == FormatMode::kSFloat) { Result r = token->ConvertToDouble(); if (!r.IsSuccess()) return r; @@ -427,10 +436,12 @@ Result Parser::ProcessVertexDataBlock(const SectionParser::Section& section) { auto buffer = MakeUnique<Buffer>(BufferType::kVertex); auto* buf = buffer.get(); buffer->SetName("Vertices" + std::to_string(i)); - buffer->SetFormat(headers[i].format.get()); - buffer->SetData(std::move(values[i])); + buffer->SetFormat(headers[i].format); + Result r = buffer->SetData(std::move(values[i])); + if (!r.IsSuccess()) + return r; + script_->AddBuffer(std::move(buffer)); - script_->RegisterFormat(std::move(headers[i].format)); pipeline->AddVertexBuffer(buf, headers[i].location); } diff --git a/src/vkscript/parser_test.cc b/src/vkscript/parser_test.cc index ab072af..676e75e 100644 --- a/src/vkscript/parser_test.cc +++ b/src/vkscript/parser_test.cc @@ -385,8 +385,8 @@ TEST_F(VkScriptParserTest, VertexDataHeaderGlslString) { auto& segs1 = buffers[1]->GetFormat()->GetSegments(); ASSERT_EQ(2U, segs1.size()); - EXPECT_EQ(FormatMode::kSFloat, segs1[0].GetComponent()->mode); - EXPECT_EQ(FormatMode::kSFloat, segs1[1].GetComponent()->mode); + EXPECT_EQ(FormatMode::kSFloat, segs1[0].GetFormatMode()); + EXPECT_EQ(FormatMode::kSFloat, segs1[1].GetFormatMode()); EXPECT_EQ(static_cast<uint32_t>(0), buffers[1]->ElementCount()); ASSERT_EQ(BufferType::kVertex, buffers[2]->GetBufferType()); @@ -396,9 +396,9 @@ TEST_F(VkScriptParserTest, VertexDataHeaderGlslString) { auto& segs2 = buffers[2]->GetFormat()->GetSegments(); ASSERT_EQ(4, segs2.size()); - EXPECT_EQ(FormatMode::kSInt, segs2[0].GetComponent()->mode); - EXPECT_EQ(FormatMode::kSInt, segs2[1].GetComponent()->mode); - EXPECT_EQ(FormatMode::kSInt, segs2[2].GetComponent()->mode); + EXPECT_EQ(FormatMode::kSInt, segs2[0].GetFormatMode()); + EXPECT_EQ(FormatMode::kSInt, segs2[1].GetFormatMode()); + EXPECT_EQ(FormatMode::kSInt, segs2[2].GetFormatMode()); EXPECT_TRUE(segs2[3].IsPadding()); EXPECT_EQ(static_cast<uint32_t>(0), buffers[2]->ElementCount()); } @@ -457,7 +457,6 @@ TEST_F(VkScriptParserTest, VertexDataRows) { std::vector<float> seg_0 = {-1.f, -1.f, 0.25f, 0, 0.25f, -1.f, 0.25f, 0}; const auto* values_0 = buffers[1]->GetValues<float>(); - ASSERT_EQ(seg_0.size(), buffers[1]->ValueCount()); for (size_t i = 0; i < seg_0.size(); ++i) { EXPECT_FLOAT_EQ(seg_0[i], values_0[i]); } @@ -466,7 +465,6 @@ TEST_F(VkScriptParserTest, VertexDataRows) { std::vector<uint8_t> seg_1 = {255, 128, 1, 0, 255, 128, 255, 0}; const auto* values_1 = buffers[2]->GetValues<uint8_t>(); - ASSERT_EQ(seg_1.size(), buffers[2]->ValueCount()); for (size_t i = 0; i < seg_1.size(); ++i) { EXPECT_EQ(seg_1[i], values_1[i]); } diff --git a/src/vulkan/engine_vulkan.cc b/src/vulkan/engine_vulkan.cc index 4689409..f9db6b7 100644 --- a/src/vulkan/engine_vulkan.cc +++ b/src/vulkan/engine_vulkan.cc @@ -19,8 +19,8 @@ #include <utility> #include "amber/amber_vulkan.h" -#include "src/format_parser.h" #include "src/make_unique.h" +#include "src/type_parser.h" #include "src/vulkan/compute_pipeline.h" #include "src/vulkan/graphics_pipeline.h" @@ -408,10 +408,12 @@ Result EngineVulkan::DoDrawRect(const DrawRectCommand* command) { // Since draw rect command contains its vertex information and it // does not include a format of vertex buffer, we can choose any // one that is suitable. We use VK_FORMAT_R32G32_SFLOAT for it. - FormatParser fp; - auto fmt = fp.Parse("R32G32_SFLOAT"); + TypeParser parser; + auto type = parser.Parse("R32G32_SFLOAT"); + Format fmt(type.get()); + auto buf = MakeUnique<Buffer>(); - buf->SetFormat(fmt.get()); + buf->SetFormat(&fmt); buf->SetData(std::move(values)); auto vertex_buffer = MakeUnique<VertexBuffer>(device_.get()); diff --git a/src/vulkan/vertex_buffer_test.cc b/src/vulkan/vertex_buffer_test.cc index ae170ae..c023d5a 100644 --- a/src/vulkan/vertex_buffer_test.cc +++ b/src/vulkan/vertex_buffer_test.cc @@ -19,8 +19,8 @@ #include "amber/value.h" #include "gtest/gtest.h" #include "src/format.h" -#include "src/format_parser.h" #include "src/make_unique.h" +#include "src/type_parser.h" #include "src/vulkan/transfer_buffer.h" namespace amber { @@ -97,10 +97,11 @@ TEST_F(VertexBufferTest, R8G8B8A8_UINT) { values[2].SetIntValue(27); values[3].SetIntValue(255); - FormatParser fp; - auto fmt = fp.Parse("R8G8B8A8_UINT"); + TypeParser parser; + auto type = parser.Parse("R8G8B8A8_UINT"); + Format fmt(type.get()); + Result r = SetIntData(0, &fmt, values); - Result r = SetIntData(0, fmt.get(), values); const uint8_t* ptr = static_cast<const uint8_t*>(GetVkBufferPtr()); EXPECT_EQ(55, ptr[0]); EXPECT_EQ(3, ptr[1]); @@ -115,10 +116,11 @@ TEST_F(VertexBufferTest, R16G16B16A16_UINT) { values[2].SetIntValue(27); values[3].SetIntValue(255); - FormatParser fp; - auto fmt = fp.Parse("R16G16B16A16_UINT"); + TypeParser parser; + auto type = parser.Parse("R16G16B16A16_UINT"); + Format fmt(type.get()); + Result r = SetIntData(0, &fmt, values); - Result r = SetIntData(0, fmt.get(), values); const uint16_t* ptr = static_cast<const uint16_t*>(GetVkBufferPtr()); EXPECT_EQ(55, ptr[0]); EXPECT_EQ(3, ptr[1]); @@ -133,10 +135,11 @@ TEST_F(VertexBufferTest, R32G32B32A32_UINT) { values[2].SetIntValue(27); values[3].SetIntValue(255); - FormatParser fp; - auto fmt = fp.Parse("R32G32B32A32_UINT"); + TypeParser parser; + auto type = parser.Parse("R32G32B32A32_UINT"); + Format fmt(type.get()); + Result r = SetIntData(0, &fmt, values); - Result r = SetIntData(0, fmt.get(), values); const uint32_t* ptr = static_cast<const uint32_t*>(GetVkBufferPtr()); EXPECT_EQ(55, ptr[0]); EXPECT_EQ(3, ptr[1]); @@ -151,10 +154,11 @@ TEST_F(VertexBufferTest, R64G64B64A64_UINT) { values[2].SetIntValue(27); values[3].SetIntValue(255); - FormatParser fp; - auto fmt = fp.Parse("R64G64B64A64_UINT"); + TypeParser parser; + auto type = parser.Parse("R64G64B64A64_UINT"); + Format fmt(type.get()); + Result r = SetIntData(0, &fmt, values); - Result r = SetIntData(0, fmt.get(), values); const uint64_t* ptr = static_cast<const uint64_t*>(GetVkBufferPtr()); EXPECT_EQ(55, ptr[0]); EXPECT_EQ(3, ptr[1]); @@ -169,11 +173,12 @@ TEST_F(VertexBufferTest, R8G8B8A8_SNORM) { values[2].SetIntValue(static_cast<uint64_t>(-128)); values[3].SetIntValue(127); - FormatParser fp; - auto fmt = fp.Parse("R8G8B8A8_SNORM"); - - Result r = SetIntData(0, fmt.get(), values); + TypeParser parser; + auto type = parser.Parse("R8G8B8A8_SNORM"); + Format fmt(type.get()); + Result r = SetIntData(0, &fmt, values); const int8_t* ptr = static_cast<const int8_t*>(GetVkBufferPtr()); + EXPECT_EQ(-55, ptr[0]); EXPECT_EQ(3, ptr[1]); EXPECT_EQ(-128, ptr[2]); @@ -187,10 +192,11 @@ TEST_F(VertexBufferTest, R16G16B16A16_SNORM) { values[2].SetIntValue(static_cast<uint64_t>(-27)); values[3].SetIntValue(255); - FormatParser fp; - auto fmt = fp.Parse("R16G16B16A16_SNORM"); + TypeParser parser; + auto type = parser.Parse("R16G16B16A16_SNORM"); + Format fmt(type.get()); + Result r = SetIntData(0, &fmt, values); - Result r = SetIntData(0, fmt.get(), values); const int16_t* ptr = static_cast<const int16_t*>(GetVkBufferPtr()); EXPECT_EQ(-55, ptr[0]); EXPECT_EQ(3, ptr[1]); @@ -205,10 +211,11 @@ TEST_F(VertexBufferTest, R32G32B32A32_SINT) { values[2].SetIntValue(static_cast<uint64_t>(-27)); values[3].SetIntValue(255); - FormatParser fp; - auto fmt = fp.Parse("R32G32B32A32_SINT"); + TypeParser parser; + auto type = parser.Parse("R32G32B32A32_SINT"); + Format fmt(type.get()); + Result r = SetIntData(0, &fmt, values); - Result r = SetIntData(0, fmt.get(), values); const int32_t* ptr = static_cast<const int32_t*>(GetVkBufferPtr()); EXPECT_EQ(-55, ptr[0]); EXPECT_EQ(3, ptr[1]); @@ -223,10 +230,11 @@ TEST_F(VertexBufferTest, R64G64B64A64_SINT) { values[2].SetIntValue(static_cast<uint64_t>(-27)); values[3].SetIntValue(255); - FormatParser fp; - auto fmt = fp.Parse("R64G64B64A64_SINT"); + TypeParser parser; + auto type = parser.Parse("R64G64B64A64_SINT"); + Format fmt(type.get()); + Result r = SetIntData(0, &fmt, values); - Result r = SetIntData(0, fmt.get(), values); const int64_t* ptr = static_cast<const int64_t*>(GetVkBufferPtr()); EXPECT_EQ(-55, ptr[0]); EXPECT_EQ(3, ptr[1]); @@ -240,10 +248,11 @@ TEST_F(VertexBufferTest, R32G32B32_SFLOAT) { values[1].SetDoubleValue(14.0); values[2].SetDoubleValue(0.1171875); - FormatParser fp; - auto fmt = fp.Parse("R32G32B32_SFLOAT"); + TypeParser parser; + auto type = parser.Parse("R32G32B32_SFLOAT"); + Format fmt(type.get()); + Result r = SetDoubleData(0, &fmt, values); - Result r = SetDoubleData(0, fmt.get(), values); const float* ptr = static_cast<const float*>(GetVkBufferPtr()); EXPECT_FLOAT_EQ(-6.0f, ptr[0]); EXPECT_FLOAT_EQ(14.0f, ptr[1]); @@ -256,10 +265,11 @@ TEST_F(VertexBufferTest, R64G64B64_SFLOAT) { values[1].SetDoubleValue(14.0); values[2].SetDoubleValue(0.1171875); - FormatParser fp; - auto fmt = fp.Parse("R64G64B64_SFLOAT"); + TypeParser parser; + auto type = parser.Parse("R64G64B64_SFLOAT"); + Format fmt(type.get()); + Result r = SetDoubleData(0, &fmt, values); - Result r = SetDoubleData(0, fmt.get(), values); const double* ptr = static_cast<const double*>(GetVkBufferPtr()); EXPECT_DOUBLE_EQ(-6.0, ptr[0]); EXPECT_DOUBLE_EQ(14.0, ptr[1]); |