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; } HasDepthComponent()117 bool HasDepthComponent() const { 118 return format_type_ == FormatType::kD16_UNORM || 119 format_type_ == FormatType::kD16_UNORM_S8_UINT || 120 format_type_ == FormatType::kD24_UNORM_S8_UINT || 121 format_type_ == FormatType::kD32_SFLOAT || 122 format_type_ == FormatType::kD32_SFLOAT_S8_UINT || 123 format_type_ == FormatType::kX8_D24_UNORM_PACK32; 124 } HasStencilComponent()125 bool HasStencilComponent() const { 126 return format_type_ == FormatType::kD24_UNORM_S8_UINT || 127 format_type_ == FormatType::kD16_UNORM_S8_UINT || 128 format_type_ == FormatType::kD32_SFLOAT_S8_UINT || 129 format_type_ == FormatType::kS8_UINT; 130 } 131 132 /// Returns true if the format components are normalized. IsNormalized()133 bool IsNormalized() const { 134 if (type_->IsNumber() && IsNormalized(type_->AsNumber()->GetFormatMode())) 135 return true; 136 137 if (type_->IsList()) { 138 for (auto& member : type_->AsList()->Members()) { 139 if (!IsNormalized(member.mode)) { 140 return false; 141 } 142 } 143 return true; 144 } 145 return false; 146 } 147 148 /// Returns the number of input values required for an item of this format. 149 /// This differs from ValuesPerElement because it doesn't take padding into 150 /// account. 151 uint32_t InputNeededPerElement() const; 152 153 /// Returns true if all components of this format are an 8 bit signed int. IsInt8()154 bool IsInt8() const { 155 return type_->IsNumber() && 156 type::Type::IsInt8(type_->AsNumber()->GetFormatMode(), 157 type_->AsNumber()->NumBits()); 158 } 159 /// Returns true if all components of this format are a 16 bit signed int. IsInt16()160 bool IsInt16() const { 161 return type_->IsNumber() && 162 type::Type::IsInt16(type_->AsNumber()->GetFormatMode(), 163 type_->AsNumber()->NumBits()); 164 } 165 /// Returns true if all components of this format are a 32 bit signed int. IsInt32()166 bool IsInt32() const { 167 return type_->IsNumber() && 168 type::Type::IsInt32(type_->AsNumber()->GetFormatMode(), 169 type_->AsNumber()->NumBits()); 170 } 171 /// Returns true if all components of this format are a 64 bit signed int. IsInt64()172 bool IsInt64() const { 173 return type_->IsNumber() && 174 type::Type::IsInt64(type_->AsNumber()->GetFormatMode(), 175 type_->AsNumber()->NumBits()); 176 } 177 /// Returns true if all components of this format are a 8 bit unsigned int. IsUint8()178 bool IsUint8() const { 179 return type_->IsNumber() && 180 type::Type::IsUint8(type_->AsNumber()->GetFormatMode(), 181 type_->AsNumber()->NumBits()); 182 } 183 /// Returns true if all components of this format are a 16 bit unsigned int. IsUint16()184 bool IsUint16() const { 185 return type_->IsNumber() && 186 type::Type::IsUint16(type_->AsNumber()->GetFormatMode(), 187 type_->AsNumber()->NumBits()); 188 } 189 /// Returns true if all components of this format are a 32 bit unsigned int. IsUint32()190 bool IsUint32() const { 191 return type_->IsNumber() && 192 type::Type::IsUint32(type_->AsNumber()->GetFormatMode(), 193 type_->AsNumber()->NumBits()); 194 } 195 /// Returns true if all components of this format are a 64 bit unsigned int. IsUint64()196 bool IsUint64() const { 197 return type_->IsNumber() && 198 type::Type::IsUint64(type_->AsNumber()->GetFormatMode(), 199 type_->AsNumber()->NumBits()); 200 } 201 /// Returns true if all components of this format are a 32 bit float. IsFloat32()202 bool IsFloat32() const { 203 return type_->IsNumber() && 204 type::Type::IsFloat32(type_->AsNumber()->GetFormatMode(), 205 type_->AsNumber()->NumBits()); 206 } 207 /// Returns true if all components of this format are a 64 bit float. IsFloat64()208 bool IsFloat64() const { 209 return type_->IsNumber() && 210 type::Type::IsFloat64(type_->AsNumber()->GetFormatMode(), 211 type_->AsNumber()->NumBits()); 212 } 213 GenerateNameForTesting()214 std::string GenerateNameForTesting() const { return GenerateName(); } 215 216 private: 217 void RebuildSegments(); 218 uint32_t AddSegmentsForType(type::Type* type); 219 bool NeedsPadding(type::Type* t) const; 220 // Returns true if a segment was added, false if we packed the requested 221 // segment into previously allocated space. 222 bool AddSegment(const Segment& seg); 223 void AddPaddedSegment(uint32_t size); 224 void AddPaddedSegmentPackable(uint32_t size); 225 uint32_t CalcTypeBaseAlignmentInBytes(type::Type* s) const; 226 uint32_t CalcStructBaseAlignmentInBytes(type::Struct* s) const; 227 uint32_t CalcVecBaseAlignmentInBytes(type::Number* n) const; 228 uint32_t CalcArrayBaseAlignmentInBytes(type::Type* t) const; 229 uint32_t CalcMatrixBaseAlignmentInBytes(type::Number* m) const; 230 uint32_t CalcListBaseAlignmentInBytes(type::List* l) const; 231 232 /// Generates the image format name for this format if possible. Returns 233 /// the name if generated or "" otherwise. 234 std::string GenerateName() const; 235 236 FormatType format_type_ = FormatType::kUnknown; 237 Layout layout_ = Layout::kStd430; 238 type::Type* type_; 239 std::vector<FormatComponentType> type_names_; 240 std::vector<Segment> segments_; 241 }; 242 243 } // namespace amber 244 245 #endif // SRC_FORMAT_H_ 246