1 // Copyright 2018 The Amber Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef SRC_FORMAT_H_ 16 #define SRC_FORMAT_H_ 17 18 #include <cassert> 19 #include <cstdint> 20 #include <string> 21 #include <vector> 22 23 #include "src/format_data.h" 24 #include "src/make_unique.h" 25 #include "src/type.h" 26 27 namespace amber { 28 29 /// The format class describes requested data formats. (eg. R8G8B8A8_UINT). 30 /// 31 /// There is a distinction between the input values needed and the values needed 32 /// for a given format. The input values is the number needed to be read to fill 33 /// out the format. The number of values is the number needed in memory to fill 34 /// out the format. These two numbers maybe different. The number of values will 35 /// always be equal or greater then the number of input values needed. 36 /// 37 /// The place these differ is a) std140 layouts and b) vectors with 3 items. In 38 /// both those cases we inflate the to 4 elements. So the input data will be 39 /// smaller then the values per element. 40 class Format { 41 public: 42 enum Layout { kStd140 = 0, kStd430 }; 43 44 class Segment { 45 public: Segment(uint32_t num_bytes)46 explicit Segment(uint32_t num_bytes) 47 : is_padding_(true), num_bits_(num_bytes * 8) {} Segment(FormatComponentType name,FormatMode mode,uint32_t num_bits)48 Segment(FormatComponentType name, FormatMode mode, uint32_t num_bits) 49 : name_(name), mode_(mode), num_bits_(num_bits) {} 50 IsPadding()51 bool IsPadding() const { return is_padding_; } PaddingBytes()52 uint32_t PaddingBytes() const { return num_bits_ / 8; } 53 GetName()54 FormatComponentType GetName() const { return name_; } GetFormatMode()55 FormatMode GetFormatMode() const { return mode_; } GetNumBits()56 uint32_t GetNumBits() const { return num_bits_; } 57 SizeInBytes()58 uint32_t SizeInBytes() const { return num_bits_ / 8; } 59 60 // The packable flag can be set on padding segments. This means, the next 61 // byte, if it's the same type as this packing, can be inserted before 62 // this packing segment as long as it fits within the pack size, removing 63 // that much pack space. IsPackable()64 bool IsPackable() const { return is_packable_; } SetPackable(bool packable)65 void SetPackable(bool packable) { is_packable_ = packable; } 66 67 private: 68 bool is_padding_ = false; 69 bool is_packable_ = false; 70 FormatComponentType name_ = FormatComponentType::kR; 71 FormatMode mode_ = FormatMode::kSInt; 72 uint32_t num_bits_ = 0; 73 }; 74 75 /// Creates a format of unknown type. 76 explicit Format(type::Type* type); 77 ~Format(); 78 IsNormalized(FormatMode mode)79 static bool IsNormalized(FormatMode mode) { 80 return mode == FormatMode::kUNorm || mode == FormatMode::kSNorm || 81 mode == FormatMode::kSRGB; 82 } 83 84 /// Returns true if |b| describes the same format as this object. 85 bool Equal(const Format* b) const; 86 87 /// Sets the type of the format. For image types this maps closely to the 88 /// list of Vulkan formats. For data types, this maybe Unknown if the data 89 /// type can not be represented by the image format (e.g. matrix types) SetFormatType(FormatType type)90 void SetFormatType(FormatType type) { format_type_ = type; } GetFormatType()91 FormatType GetFormatType() const { return format_type_; } 92 93 void SetLayout(Layout layout); GetLayout()94 Layout GetLayout() const { return layout_; } 95 GetType()96 type::Type* GetType() const { return type_; } 97 98 /// Returns a pointer to the only type in this format. Only valid if 99 /// there is only an int or float type, nullptr otherwise. GetOnlyType()100 type::Type* GetOnlyType() const { 101 if (type_->IsNumber()) 102 return type_; 103 return nullptr; 104 } 105 IsPacked()106 bool IsPacked() const { 107 return type_->IsList() && type_->AsList()->IsPacked(); 108 } 109 110 /// The segment is the individual pieces of the components including padding. GetSegments()111 const std::vector<Segment>& GetSegments() const { return segments_; } 112 113 /// Returns the number of bytes this format requires. 114 uint32_t SizeInBytes() const; 115 IsFormatKnown()116 bool IsFormatKnown() const { return format_type_ != FormatType::kUnknown; } HasStencilComponent()117 bool HasStencilComponent() const { 118 return format_type_ == FormatType::kD24_UNORM_S8_UINT || 119 format_type_ == FormatType::kD16_UNORM_S8_UINT || 120 format_type_ == FormatType::kD32_SFLOAT_S8_UINT || 121 format_type_ == FormatType::kS8_UINT; 122 } 123 124 /// Returns true if the format components are normalized. IsNormalized()125 bool IsNormalized() const { 126 if (type_->IsNumber() && IsNormalized(type_->AsNumber()->GetFormatMode())) 127 return true; 128 129 if (type_->IsList()) { 130 for (auto& member : type_->AsList()->Members()) { 131 if (!IsNormalized(member.mode)) { 132 return false; 133 } 134 } 135 return true; 136 } 137 return false; 138 } 139 140 /// Returns the number of input values required for an item of this format. 141 /// This differs from ValuesPerElement because it doesn't take padding into 142 /// account. 143 uint32_t InputNeededPerElement() const; 144 145 /// Returns true if all components of this format are an 8 bit signed int. IsInt8()146 bool IsInt8() const { 147 return type_->IsNumber() && 148 type::Type::IsInt8(type_->AsNumber()->GetFormatMode(), 149 type_->AsNumber()->NumBits()); 150 } 151 /// Returns true if all components of this format are a 16 bit signed int. IsInt16()152 bool IsInt16() const { 153 return type_->IsNumber() && 154 type::Type::IsInt16(type_->AsNumber()->GetFormatMode(), 155 type_->AsNumber()->NumBits()); 156 } 157 /// Returns true if all components of this format are a 32 bit signed int. IsInt32()158 bool IsInt32() const { 159 return type_->IsNumber() && 160 type::Type::IsInt32(type_->AsNumber()->GetFormatMode(), 161 type_->AsNumber()->NumBits()); 162 } 163 /// Returns true if all components of this format are a 64 bit signed int. IsInt64()164 bool IsInt64() const { 165 return type_->IsNumber() && 166 type::Type::IsInt64(type_->AsNumber()->GetFormatMode(), 167 type_->AsNumber()->NumBits()); 168 } 169 /// Returns true if all components of this format are a 8 bit unsigned int. IsUint8()170 bool IsUint8() const { 171 return type_->IsNumber() && 172 type::Type::IsUint8(type_->AsNumber()->GetFormatMode(), 173 type_->AsNumber()->NumBits()); 174 } 175 /// Returns true if all components of this format are a 16 bit unsigned int. IsUint16()176 bool IsUint16() const { 177 return type_->IsNumber() && 178 type::Type::IsUint16(type_->AsNumber()->GetFormatMode(), 179 type_->AsNumber()->NumBits()); 180 } 181 /// Returns true if all components of this format are a 32 bit unsigned int. IsUint32()182 bool IsUint32() const { 183 return type_->IsNumber() && 184 type::Type::IsUint32(type_->AsNumber()->GetFormatMode(), 185 type_->AsNumber()->NumBits()); 186 } 187 /// Returns true if all components of this format are a 64 bit unsigned int. IsUint64()188 bool IsUint64() const { 189 return type_->IsNumber() && 190 type::Type::IsUint64(type_->AsNumber()->GetFormatMode(), 191 type_->AsNumber()->NumBits()); 192 } 193 /// Returns true if all components of this format are a 32 bit float. IsFloat32()194 bool IsFloat32() const { 195 return type_->IsNumber() && 196 type::Type::IsFloat32(type_->AsNumber()->GetFormatMode(), 197 type_->AsNumber()->NumBits()); 198 } 199 /// Returns true if all components of this format are a 64 bit float. IsFloat64()200 bool IsFloat64() const { 201 return type_->IsNumber() && 202 type::Type::IsFloat64(type_->AsNumber()->GetFormatMode(), 203 type_->AsNumber()->NumBits()); 204 } 205 GenerateNameForTesting()206 std::string GenerateNameForTesting() const { return GenerateName(); } 207 208 private: 209 void RebuildSegments(); 210 uint32_t AddSegmentsForType(type::Type* type); 211 bool NeedsPadding(type::Type* t) const; 212 // Returns true if a segment was added, false if we packed the requested 213 // segment into previously allocated space. 214 bool AddSegment(const Segment& seg); 215 void AddPaddedSegment(uint32_t size); 216 void AddPaddedSegmentPackable(uint32_t size); 217 uint32_t CalcTypeBaseAlignmentInBytes(type::Type* s) const; 218 uint32_t CalcStructBaseAlignmentInBytes(type::Struct* s) const; 219 uint32_t CalcVecBaseAlignmentInBytes(type::Number* n) const; 220 uint32_t CalcArrayBaseAlignmentInBytes(type::Type* t) const; 221 uint32_t CalcMatrixBaseAlignmentInBytes(type::Number* m) const; 222 uint32_t CalcListBaseAlignmentInBytes(type::List* l) const; 223 224 /// Generates the image format name for this format if possible. Returns 225 /// the name if generated or "" otherwise. 226 std::string GenerateName() const; 227 228 FormatType format_type_ = FormatType::kUnknown; 229 Layout layout_ = Layout::kStd430; 230 type::Type* type_; 231 std::vector<FormatComponentType> type_names_; 232 std::vector<Segment> segments_; 233 }; 234 235 } // namespace amber 236 237 #endif // SRC_FORMAT_H_ 238