• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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