1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // vk_format_utils:
7 // Helper for Vulkan format code.
8
9 #ifndef LIBANGLE_RENDERER_VULKAN_VK_FORMAT_UTILS_H_
10 #define LIBANGLE_RENDERER_VULKAN_VK_FORMAT_UTILS_H_
11
12 #include "libANGLE/formatutils.h"
13 #include "libANGLE/renderer/Format.h"
14 #include "libANGLE/renderer/copyvertex.h"
15 #include "libANGLE/renderer/renderer_utils.h"
16 #include "libANGLE/renderer/vulkan/vk_headers.h"
17 #include "platform/FeaturesVk.h"
18
19 #include <array>
20
21 namespace gl
22 {
23 struct SwizzleState;
24 class TextureCapsMap;
25 } // namespace gl
26
27 namespace rx
28 {
29 class RendererVk;
30 class ContextVk;
31
32 namespace vk
33 {
34 // VkFormat values in range [0, kNumVkFormats) are used as indices in various tables.
35 constexpr uint32_t kNumVkFormats = 185;
36
37 struct ImageFormatInitInfo final
38 {
39 angle::FormatID format;
40 VkFormat vkFormat;
41 InitializeTextureDataFunction initializer;
42 };
43
44 struct BufferFormatInitInfo final
45 {
46 angle::FormatID format;
47 VkFormat vkFormat;
48 bool vkFormatIsPacked;
49 VertexCopyFunction vertexLoadFunction;
50 bool vertexLoadRequiresConversion;
51 };
52
53 // Describes a Vulkan format. For more information on formats in the Vulkan back-end please see
54 // https://chromium.googlesource.com/angle/angle/+/master/src/libANGLE/renderer/vulkan/doc/FormatTablesAndEmulation.md
55 struct Format final : private angle::NonCopyable
56 {
57 Format();
58
validfinal59 bool valid() const { return internalFormat != 0; }
60
61 // The intended format is the front-end format. For Textures this usually correponds to a
62 // GLenum in the headers. Buffer formats don't always have a corresponding GLenum type.
63 // Some Surface formats and unsized types also don't have a corresponding GLenum.
intendedFormatfinal64 const angle::Format &intendedFormat() const { return angle::Format::Get(intendedFormatID); }
65
66 // The actual Image format is used to implement the front-end format for Texture/Renderbuffers.
actualImageFormatfinal67 const angle::Format &actualImageFormat() const
68 {
69 return angle::Format::Get(actualImageFormatID);
70 }
71
72 // The actual Buffer format is used to implement the front-end format for Buffers.
actualBufferFormatfinal73 const angle::Format &actualBufferFormat() const
74 {
75 return angle::Format::Get(actualBufferFormatID);
76 }
77
78 // The |internalFormat| always correponds to a valid GLenum type. For types that don't have a
79 // corresponding GLenum we do our best to specify a GLenum that is "close".
getInternalFormatInfofinal80 const gl::InternalFormat &getInternalFormatInfo(GLenum type) const
81 {
82 return gl::GetInternalFormatInfo(internalFormat, type);
83 }
84
85 // Returns buffer alignment for image-copy operations (to or from a buffer).
86 size_t getImageCopyBufferAlignment() const;
87
88 // Returns true if the Image format has more channels than the ANGLE format.
89 bool hasEmulatedImageChannels() const;
90
91 // This is an auto-generated method in vk_format_table_autogen.cpp.
92 void initialize(RendererVk *renderer, const angle::Format &angleFormat);
93
94 // These are used in the format table init.
95 void initImageFallback(RendererVk *renderer, const ImageFormatInitInfo *info, int numInfo);
96 void initBufferFallback(RendererVk *renderer, const BufferFormatInitInfo *info, int numInfo);
97
98 angle::FormatID intendedFormatID;
99 GLenum internalFormat;
100 angle::FormatID actualImageFormatID;
101 VkFormat vkImageFormat;
102 angle::FormatID actualBufferFormatID;
103 VkFormat vkBufferFormat;
104
105 InitializeTextureDataFunction imageInitializerFunction;
106 LoadFunctionMap textureLoadFunctions;
107 VertexCopyFunction vertexLoadFunction;
108
109 bool vertexLoadRequiresConversion;
110 bool vkBufferFormatIsPacked;
111 bool vkFormatIsInt;
112 bool vkFormatIsUnsigned;
113 };
114
115 bool operator==(const Format &lhs, const Format &rhs);
116 bool operator!=(const Format &lhs, const Format &rhs);
117
118 class FormatTable final : angle::NonCopyable
119 {
120 public:
121 FormatTable();
122 ~FormatTable();
123
124 // Also initializes the TextureCapsMap and the compressedTextureCaps in the Caps instance.
125 void initialize(RendererVk *renderer,
126 gl::TextureCapsMap *outTextureCapsMap,
127 std::vector<GLenum> *outCompressedTextureFormats);
128
129 ANGLE_INLINE const Format &operator[](GLenum internalFormat) const
130 {
131 angle::FormatID formatID = angle::Format::InternalFormatToID(internalFormat);
132 return mFormatData[static_cast<size_t>(formatID)];
133 }
134
135 ANGLE_INLINE const Format &operator[](angle::FormatID formatID) const
136 {
137 return mFormatData[static_cast<size_t>(formatID)];
138 }
139
140 private:
141 // The table data is indexed by angle::FormatID.
142 std::array<Format, angle::kNumANGLEFormats> mFormatData;
143 };
144
145 // This will return a reference to a VkFormatProperties with the feature flags supported
146 // if the format is a mandatory format described in section 31.3.3. Required Format Support
147 // of the Vulkan spec. If the vkFormat isn't mandatory, it will return a VkFormatProperties
148 // initialized to 0.
149 const VkFormatProperties &GetMandatoryFormatSupport(VkFormat vkFormat);
150
151 VkImageUsageFlags GetMaximalImageUsageFlags(RendererVk *renderer, VkFormat format);
152
153 } // namespace vk
154
155 // Checks if a vkFormat supports all the features needed to use it as a GL texture format
156 bool HasFullTextureFormatSupport(RendererVk *renderer, VkFormat vkFormat);
157 // Checks if a vkFormat supports all the features except texture filtering
158 bool HasNonFilterableTextureFormatSupport(RendererVk *renderer, VkFormat vkFormat);
159 // Checks if a vkFormat supports all the features except rendering
160 bool HasNonRenderableTextureFormatSupport(RendererVk *renderer, VkFormat vkFormat);
161
162 // Returns the alignment for a buffer to be used with the vertex input stage in Vulkan. This
163 // calculation is listed in the Vulkan spec at the end of the section 'Vertex Input Description'.
164 size_t GetVertexInputAlignment(const vk::Format &format);
165
166 void MapSwizzleState(const ContextVk *contextVk,
167 const vk::Format &format,
168 const bool sized,
169 const gl::SwizzleState &swizzleState,
170 gl::SwizzleState *swizzleStateOut);
171
172 namespace vk
173 {
174
ConvertToNonLinear(VkFormat format)175 ANGLE_INLINE VkFormat ConvertToNonLinear(VkFormat format)
176 {
177 switch (format)
178 {
179 case VK_FORMAT_R8_UNORM:
180 return VK_FORMAT_R8_SRGB;
181 case VK_FORMAT_R8G8_UNORM:
182 return VK_FORMAT_R8G8_SRGB;
183 case VK_FORMAT_R8G8B8_UNORM:
184 return VK_FORMAT_R8G8B8_SRGB;
185 case VK_FORMAT_B8G8R8_UNORM:
186 return VK_FORMAT_B8G8R8_SRGB;
187 case VK_FORMAT_R8G8B8A8_UNORM:
188 return VK_FORMAT_R8G8B8A8_SRGB;
189 case VK_FORMAT_B8G8R8A8_UNORM:
190 return VK_FORMAT_B8G8R8A8_SRGB;
191 case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
192 return VK_FORMAT_BC1_RGB_SRGB_BLOCK;
193 case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
194 return VK_FORMAT_BC1_RGBA_SRGB_BLOCK;
195 case VK_FORMAT_BC2_UNORM_BLOCK:
196 return VK_FORMAT_BC2_SRGB_BLOCK;
197 case VK_FORMAT_BC3_UNORM_BLOCK:
198 return VK_FORMAT_BC3_SRGB_BLOCK;
199 case VK_FORMAT_BC7_UNORM_BLOCK:
200 return VK_FORMAT_BC7_SRGB_BLOCK;
201 case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
202 return VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK;
203 case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
204 return VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK;
205 case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
206 return VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK;
207 case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
208 return VK_FORMAT_ASTC_4x4_SRGB_BLOCK;
209 case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
210 return VK_FORMAT_ASTC_5x4_SRGB_BLOCK;
211 case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
212 return VK_FORMAT_ASTC_5x5_SRGB_BLOCK;
213 case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
214 return VK_FORMAT_ASTC_6x5_SRGB_BLOCK;
215 case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
216 return VK_FORMAT_ASTC_6x6_SRGB_BLOCK;
217 case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
218 return VK_FORMAT_ASTC_8x5_SRGB_BLOCK;
219 case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
220 return VK_FORMAT_ASTC_8x6_SRGB_BLOCK;
221 case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
222 return VK_FORMAT_ASTC_8x8_SRGB_BLOCK;
223 case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
224 return VK_FORMAT_ASTC_10x5_SRGB_BLOCK;
225 case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
226 return VK_FORMAT_ASTC_10x6_SRGB_BLOCK;
227 case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
228 return VK_FORMAT_ASTC_10x8_SRGB_BLOCK;
229 case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
230 return VK_FORMAT_ASTC_10x10_SRGB_BLOCK;
231 case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
232 return VK_FORMAT_ASTC_12x10_SRGB_BLOCK;
233 case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
234 return VK_FORMAT_ASTC_12x12_SRGB_BLOCK;
235 default:
236 return VK_FORMAT_UNDEFINED;
237 }
238 }
239
ConvertToLinear(VkFormat format)240 ANGLE_INLINE VkFormat ConvertToLinear(VkFormat format)
241 {
242 switch (format)
243 {
244 case VK_FORMAT_R8_SRGB:
245 return VK_FORMAT_R8_UNORM;
246 case VK_FORMAT_R8G8_SRGB:
247 return VK_FORMAT_R8G8_UNORM;
248 case VK_FORMAT_R8G8B8_SRGB:
249 return VK_FORMAT_R8G8B8_UNORM;
250 case VK_FORMAT_B8G8R8_SRGB:
251 return VK_FORMAT_B8G8R8_UNORM;
252 case VK_FORMAT_R8G8B8A8_SRGB:
253 return VK_FORMAT_R8G8B8A8_UNORM;
254 case VK_FORMAT_B8G8R8A8_SRGB:
255 return VK_FORMAT_B8G8R8A8_UNORM;
256 case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
257 return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
258 case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
259 return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
260 case VK_FORMAT_BC2_SRGB_BLOCK:
261 return VK_FORMAT_BC2_UNORM_BLOCK;
262 case VK_FORMAT_BC3_SRGB_BLOCK:
263 return VK_FORMAT_BC3_UNORM_BLOCK;
264 case VK_FORMAT_BC7_SRGB_BLOCK:
265 return VK_FORMAT_BC7_UNORM_BLOCK;
266 case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
267 return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
268 case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
269 return VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
270 case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
271 return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
272 case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
273 return VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
274 case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
275 return VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
276 case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
277 return VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
278 case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
279 return VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
280 case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
281 return VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
282 case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
283 return VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
284 case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
285 return VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
286 case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
287 return VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
288 case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
289 return VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
290 case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
291 return VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
292 case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
293 return VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
294 case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
295 return VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
296 case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
297 return VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
298 case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
299 return VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
300 default:
301 return VK_FORMAT_UNDEFINED;
302 }
303 }
304
IsNonLinearFormat(VkFormat format)305 ANGLE_INLINE bool IsNonLinearFormat(VkFormat format)
306 {
307 return ConvertToLinear(format) != VK_FORMAT_UNDEFINED;
308 }
IsOverridableLinearFormat(VkFormat format)309 ANGLE_INLINE bool IsOverridableLinearFormat(VkFormat format)
310 {
311 return ConvertToNonLinear(format) != VK_FORMAT_UNDEFINED;
312 }
IsLinearFormat(VkFormat format)313 ANGLE_INLINE bool IsLinearFormat(VkFormat format)
314 {
315 return !IsNonLinearFormat(format);
316 }
317
318 } // namespace vk
319 } // namespace rx
320
321 #endif // LIBANGLE_RENDERER_VULKAN_VK_FORMAT_UTILS_H_
322