• 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; }
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