Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
formats.h
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef FLUTTER_IMPELLER_CORE_FORMATS_H_
6#define FLUTTER_IMPELLER_CORE_FORMATS_H_
7
8#include <cstdint>
9#include <functional>
10#include <memory>
11#include <string>
12
14#include "flutter/fml/logging.h"
15#include "impeller/base/mask.h"
19
20namespace impeller {
21
22enum class WindingOrder {
25};
26
27class Texture;
28
29//------------------------------------------------------------------------------
30/// @brief Specified where the allocation resides and how it is used.
31///
32enum class StorageMode {
33 //----------------------------------------------------------------------------
34 /// Allocations can be mapped onto the hosts address space and also be used by
35 /// the device.
36 ///
38 //----------------------------------------------------------------------------
39 /// Allocations can only be used by the device. This location is optimal for
40 /// use by the device. If the host needs to access these allocations, the
41 /// transfer queue must be used to transfer this allocation onto the a host
42 /// visible buffer.
43 ///
45 //----------------------------------------------------------------------------
46 /// Used by the device for temporary render targets. These allocations cannot
47 /// be transferred from and to other allocations using the transfer queue.
48 /// Render pass cannot initialize the contents of these buffers using load and
49 /// store actions.
50 ///
51 /// These allocations reside in tile memory which has higher bandwidth, lower
52 /// latency and lower power consumption. The total device memory usage is
53 /// also lower as a separate allocation does not need to be created in
54 /// device memory. Prefer using these allocations for intermediates like depth
55 /// and stencil buffers.
56 ///
58};
59
60constexpr const char* StorageModeToString(StorageMode mode) {
61 switch (mode) {
63 return "HostVisible";
65 return "DevicePrivate";
67 return "DeviceTransient";
68 }
70}
71
72//------------------------------------------------------------------------------
73/// @brief The Pixel formats supported by Impeller. The naming convention
74/// denotes the usage of the component, the bit width of that
75/// component, and then one or more qualifiers to its
76/// interpretation.
77///
78/// For instance, `kR8G8B8A8UNormIntSRGB` is a 32 bits-per-pixel
79/// format ordered in RGBA with 8 bits per component with each
80/// component expressed as an unsigned normalized integer and a
81/// conversion from sRGB to linear color space.
82///
83/// Key:
84/// R -> Red Component
85/// G -> Green Component
86/// B -> Blue Component
87/// D -> Depth Component
88/// S -> Stencil Component
89/// U -> Unsigned (Lack of this denotes a signed component)
90/// Norm -> Normalized
91/// SRGB -> sRGB to linear interpretation
92///
93/// While the effective bit width of the pixel can be determined by
94/// adding up the widths of each component, only the non-esoteric
95/// formats are tightly packed. Do not assume tight packing for the
96/// esoteric formats and use blit passes to convert to a
97/// non-esoteric pass.
98///
99enum class PixelFormat : uint8_t {
100 kUnknown,
113 kR32Float,
114 // Depth and stencil formats.
115 kS8UInt,
118 // Block-compressed formats. These are sample-only; they cannot be used as
119 // render targets, storage textures, or transient attachments, and their
120 // support varies by device (see `Capabilities::SupportsTextureCompression`).
136 // ASTC HDR has no sRGB variant; the data is already linear floating point.
139};
140
141//------------------------------------------------------------------------------
142/// @brief The family of a block-compressed pixel format. GPUs support
143/// compressed formats on a per-family basis, so each family is
144/// gated behind a single device feature.
145///
147 /// S3TC, RGTC, and BPTC (BC1 through BC7). Desktop GPUs.
148 kBC,
149 /// ETC2 and EAC. Mobile, OpenGL ES 3.0, and WebGL2.
150 kETC2,
151 /// ASTC LDR. Modern mobile and some desktop.
152 kASTC,
153 /// ASTC HDR. A separate device feature from ASTC LDR.
154 kASTCHDR,
155};
156
157/// @brief Whether `format` is a block-compressed format.
182
183/// @brief The compression family that `format` belongs to. Only valid for
184/// formats where `IsCompressed` is true.
214
215/// @brief The width, in texels, of one compression block. Uncompressed formats
216/// report 1.
242
243/// @brief The height, in texels, of one compression block. Uncompressed formats
244/// report 1.
270
271constexpr bool IsDepthWritable(PixelFormat format) {
272 switch (format) {
275 return true;
276 default:
277 return false;
278 }
279}
280
281constexpr bool IsStencilWritable(PixelFormat format) {
282 switch (format) {
286 return true;
287 default:
288 return false;
289 }
290}
291
292constexpr const char* PixelFormatToString(PixelFormat format) {
293 switch (format) {
295 return "Unknown";
297 return "A8UNormInt";
299 return "R8UNormInt";
301 return "R8G8UNormInt";
303 return "R8G8B8A8UNormInt";
305 return "R8G8B8A8UNormIntSRGB";
307 return "B8G8R8A8UNormInt";
309 return "B8G8R8A8UNormIntSRGB";
311 return "R32G32B32A32Float";
313 return "R16G16B16A16Float";
315 return "B10G10R10XR";
317 return "B10G10R10XRSRGB";
319 return "B10G10R10A10XR";
321 return "S8UInt";
323 return "D24UnormS8Uint";
325 return "D32FloatS8UInt";
327 return "R32Float";
329 return "BC1RGBAUNormInt";
331 return "BC1RGBAUNormIntSRGB";
333 return "BC3RGBAUNormInt";
335 return "BC3RGBAUNormIntSRGB";
337 return "BC5RGUNormInt";
339 return "BC7RGBAUNormInt";
341 return "BC7RGBAUNormIntSRGB";
343 return "ETC2RGB8UNormInt";
345 return "ETC2RGB8UNormIntSRGB";
347 return "ETC2RGBA8UNormInt";
349 return "ETC2RGBA8UNormIntSRGB";
351 return "ASTC4x4LDR";
353 return "ASTC4x4LDRSRGB";
355 return "ASTC8x8LDR";
357 return "ASTC8x8LDRSRGB";
359 return "ASTC4x4HDR";
361 return "ASTC8x8HDR";
362 }
364}
365
383
384enum class BlendOperation {
385 kAdd,
386 kSubtract,
388};
389
390enum class LoadAction {
391 kDontCare,
392 kLoad,
393 kClear,
394};
395
402
403constexpr const char* LoadActionToString(LoadAction action) {
404 switch (action) {
406 return "DontCare";
408 return "Load";
410 return "Clear";
411 }
412}
413
414constexpr const char* StoreActionToString(StoreAction action) {
415 switch (action) {
417 return "DontCare";
419 return "Store";
421 return "MultisampleResolve";
423 return "StoreAndMultisampleResolve";
424 }
425}
426
428 switch (action) {
430 return false;
433 return true;
434 }
436}
437
439 switch (action) {
442 return false;
445 return true;
446 }
448}
449
456
457constexpr const char* TextureTypeToString(TextureType type) {
458 switch (type) {
460 return "Texture2D";
462 return "Texture2DMultisample";
464 return "TextureCube";
466 return "TextureExternalOES";
467 }
469}
470
472 switch (type) {
476 return false;
478 return true;
479 }
480 return false;
481}
482
483enum class SampleCount : uint8_t {
484 kCount1 = 1,
485 kCount4 = 4,
486};
487
488enum class TextureUsage {
489 kUnknown = 0,
490 kShaderRead = 1 << 0,
491 kShaderWrite = 1 << 1,
492 kRenderTarget = 1 << 2,
493};
495
497
498constexpr const char* TextureUsageToString(TextureUsage usage) {
499 switch (usage) {
501 return "Unknown";
503 return "ShaderRead";
505 return "ShaderWrite";
507 return "RenderTarget";
508 }
510}
511
513
514enum class CullMode {
515 kNone,
517 kBackFace,
518};
519
520enum class IndexType : uint8_t {
521 kUnknown,
522 k16bit,
523 k32bit,
524 /// Does not use the index buffer.
525 kNone,
526};
527
528/// Decides how backend draws pixels based on input vertices.
529enum class PrimitiveType : uint8_t {
530 /// Draws a triangle for each separate set of three vertices.
531 ///
532 /// Vertices [A, B, C, D, E, F] will produce triangles
533 /// [ABC, DEF].
534 kTriangle,
535
536 /// Draws a triangle for every adjacent three vertices.
537 ///
538 /// Vertices [A, B, C, D, E, F] will produce triangles
539 /// [ABC, BCD, CDE, DEF].
541
542 /// Draws a line for each separate set of two vertices.
543 ///
544 /// Vertices [A, B, C] will produce discontinued line
545 /// [AB, BC].
546 kLine,
547
548 /// Draws a continuous line that connect every input vertices
549 ///
550 /// Vertices [A, B, C] will produce one continuous line
551 /// [ABC].
553
554 /// Draws a point at each input vertex.
555 kPoint,
556
557 /// Draws a triangle for every two vertices, after the first.
558 ///
559 /// The first vertex acts as the hub, all following vertices connect with
560 /// this hub to "fan" out from the first vertex.
561 ///
562 /// Triangle fans are not supported in Metal and need a capability check.
564};
565
566enum class PolygonMode {
567 kFill,
568 kLine,
569};
570
574
575 constexpr bool operator==(const DepthRange& other) const {
576 return z_near == other.z_near && z_far == other.z_far;
577 }
578};
579
580struct Viewport {
583
584 constexpr bool operator==(const Viewport& other) const {
585 return rect == other.rect && depth_range == other.depth_range;
586 }
587};
588
589/// @brief Describes how the texture should be sampled when the texture
590/// is being shrunk (minified) or expanded (magnified) to fit to
591/// the sample point.
592enum class MinMagFilter : uint8_t {
593 /// Select nearest to the sample point. Most widely supported.
594 kNearest,
595
596 /// Select two points and linearly interpolate between them. Some formats
597 /// may not support this.
598 kLinear,
599};
600
601/// @brief Options for selecting and filtering between mipmap levels.
602enum class MipFilter : uint8_t {
603 /// @brief The texture is sampled as if it only had a single mipmap level.
604 ///
605 /// All samples are read from level 0.
606 kBase,
607
608 /// @brief The nearst mipmap level is selected.
609 kNearest,
610
611 /// @brief Sample from the two nearest mip levels and linearly interpolate.
612 ///
613 /// If the filter falls between levels, both levels are sampled, and
614 /// their results linearly interpolated between levels.
615 kLinear,
616};
617
618enum class SamplerAddressMode : uint8_t {
620 kRepeat,
621 kMirror,
622 // More modes are almost always supported but they are usually behind
623 // extensions checks. The ones current in these structs are safe (always
624 // supported) defaults.
625
626 /// @brief decal sampling mode is only supported on devices that pass
627 /// the `Capabilities.SupportsDecalSamplerAddressMode` check.
628 kDecal,
629};
630
631enum class ColorWriteMaskBits : uint64_t {
632 kNone = 0,
633 kRed = 1 << 0,
634 kGreen = 1 << 1,
635 kBlue = 1 << 2,
636 kAlpha = 1 << 3,
637 kAll = kRed | kGreen | kBlue | kAlpha,
638};
640
642
643constexpr size_t BytesPerPixelForPixelFormat(PixelFormat format) {
644 switch (format) {
646 return 0u;
650 return 1u;
652 return 2u;
660 return 4u;
662 return 4u;
664 return 5u;
667 return 8u;
669 return 16u;
670 // Block-compressed formats have no meaningful bytes-per-pixel. Use
671 // `BytesPerBlockForPixelFormat` together with the block dimensions instead.
689 return 0u;
690 }
691 return 0u;
692}
693
694/// @brief The number of bytes used to store one block of `format`. For
695/// uncompressed formats a block is a single pixel, so this matches
696/// `BytesPerPixelForPixelFormat`.
722
723/// @brief The number of bytes required to store a `width` x `height` texel
724/// region in `format`. Block-compressed formats round the dimensions up
725/// to whole blocks. Uncompressed formats reduce to `width * height *
726/// bytes-per-pixel`.
727constexpr size_t BytesForTextureRegion(PixelFormat format,
728 int64_t width,
729 int64_t height) {
730 const size_t block_width = CompressedBlockWidthForPixelFormat(format);
731 const size_t block_height = CompressedBlockHeightForPixelFormat(format);
732 const size_t w = width <= 0 ? 0u : static_cast<size_t>(width);
733 const size_t h = height <= 0 ? 0u : static_cast<size_t>(height);
734 const size_t blocks_wide = (w + block_width - 1u) / block_width;
735 const size_t blocks_high = (h + block_height - 1u) / block_height;
736 return blocks_wide * blocks_high * BytesPerBlockForPixelFormat(format);
737}
738
739/// @brief The number of bytes in a single row of texel blocks for a texture of
740/// the given `width` in `format`.
741constexpr size_t BytesPerRowForTextureWidth(PixelFormat format, int64_t width) {
742 const size_t block_width = CompressedBlockWidthForPixelFormat(format);
743 const size_t w = width <= 0 ? 0u : static_cast<size_t>(width);
744 const size_t blocks_wide = (w + block_width - 1u) / block_width;
745 return blocks_wide * BytesPerBlockForPixelFormat(format);
746}
747
748//------------------------------------------------------------------------------
749/// @brief Describe the color attachment that will be used with this
750/// pipeline.
751///
752/// Blending at specific color attachments follows the pseudo-code:
753/// ```
754/// if (blending_enabled) {
755/// final_color.rgb = (src_color_blend_factor * new_color.rgb)
756/// <color_blend_op>
757/// (dst_color_blend_factor * old_color.rgb);
758/// final_color.a = (src_alpha_blend_factor * new_color.a)
759/// <alpha_blend_op>
760/// (dst_alpha_blend_factor * old_color.a);
761/// } else {
762/// final_color = new_color;
763/// }
764/// // IMPORTANT: The write mask is applied irrespective of whether
765/// // blending_enabled is set.
766/// final_color = final_color & write_mask;
767/// ```
768///
769/// The default blend mode is 1 - source alpha.
803
804enum class CompareFunction : uint8_t {
805 /// Comparison test never passes.
806 kNever,
807 /// Comparison test passes always passes.
808 kAlways,
809 /// Comparison test passes if new_value < current_value.
810 kLess,
811 /// Comparison test passes if new_value == current_value.
812 kEqual,
813 /// Comparison test passes if new_value <= current_value.
815 /// Comparison test passes if new_value > current_value.
816 kGreater,
817 /// Comparison test passes if new_value != current_value.
818 kNotEqual,
819 /// Comparison test passes if new_value >= current_value.
821};
822
823enum class StencilOperation : uint8_t {
824 /// Don't modify the current stencil value.
825 kKeep,
826 /// Reset the stencil value to zero.
827 kZero,
828 /// Reset the stencil value to the reference value.
830 /// Increment the current stencil value by 1. Clamp it to the maximum.
832 /// Decrement the current stencil value by 1. Clamp it to zero.
834 /// Perform a logical bitwise invert on the current stencil value.
835 kInvert,
836 /// Increment the current stencil value by 1. If at maximum, set to zero.
838 /// Decrement the current stencil value by 1. If at zero, set to maximum.
840};
841
843 //----------------------------------------------------------------------------
844 /// Indicates how to compare the value with that in the depth buffer.
845 ///
847 //----------------------------------------------------------------------------
848 /// Indicates when writes must be performed to the depth buffer.
849 ///
851
852 constexpr bool operator==(const DepthAttachmentDescriptor& o) const {
853 return depth_compare == o.depth_compare &&
855 }
856
857 constexpr size_t GetHash() const {
859 }
860};
861
863 //----------------------------------------------------------------------------
864 /// Indicates the operation to perform between the reference value and the
865 /// value in the stencil buffer. Both values have the read_mask applied to
866 /// them before performing this operation.
867 ///
869 //----------------------------------------------------------------------------
870 /// Indicates what to do when the stencil test has failed.
871 ///
873 //----------------------------------------------------------------------------
874 /// Indicates what to do when the stencil test passes but the depth test
875 /// fails.
876 ///
878 //----------------------------------------------------------------------------
879 /// Indicates what to do when both the stencil and depth tests pass.
880 ///
882
883 //----------------------------------------------------------------------------
884 /// The mask applied to the reference and stencil buffer values before
885 /// performing the stencil_compare operation.
886 ///
887 uint32_t read_mask = ~0;
888 //----------------------------------------------------------------------------
889 /// The mask applied to the new stencil value before it is written into the
890 /// stencil buffer.
891 ///
892 uint32_t write_mask = ~0;
893
901
906};
907
909 std::shared_ptr<Texture> texture;
910 std::shared_ptr<Texture> resolve_texture;
913 // The mip level of `texture` to render into. Must be < the texture's
914 // mip_count.
915 uint32_t mip_level = 0;
916 // The slice (cube map face or array layer) of `texture` to render into.
917 // Must be < the slice count implied by the texture's type.
918 uint32_t slice = 0;
919
920 bool IsValid() const;
921};
922
926
928 double clear_depth = 0.0;
929};
930
932 uint32_t clear_stencil = 0;
933};
934
935std::string AttachmentToString(const Attachment& attachment);
936
937std::string ColorAttachmentToString(const ColorAttachment& color);
938
939std::string DepthAttachmentToString(const DepthAttachment& depth);
940
941std::string StencilAttachmentToString(const StencilAttachment& stencil);
942
943} // namespace impeller
944
945namespace std {
946
947template <>
948struct hash<impeller::DepthAttachmentDescriptor> {
949 constexpr std::size_t operator()(
950 const impeller::DepthAttachmentDescriptor& des) const {
951 return des.GetHash();
952 }
953};
954
955template <>
956struct hash<impeller::StencilAttachmentDescriptor> {
957 constexpr std::size_t operator()(
958 const impeller::StencilAttachmentDescriptor& des) const {
959 return des.GetHash();
960 }
961};
962
963} // namespace std
964
965#endif // FLUTTER_IMPELLER_CORE_FORMATS_H_
uint32_t uint32_t * format
#define FML_UNREACHABLE()
Definition logging.h:128
#define IMPELLER_ENUM_IS_MASK(enum_name)
Declare this in the "impeller" namespace to make the enum maskable.
Definition mask.h:21
constexpr std::size_t HashCombine()
constexpr size_t BytesPerPixelForPixelFormat(PixelFormat format)
Definition formats.h:643
constexpr bool CanClearAttachment(LoadAction action)
Definition formats.h:427
constexpr size_t CompressedBlockHeightForPixelFormat(PixelFormat format)
The height, in texels, of one compression block. Uncompressed formats report 1.
Definition formats.h:245
std::string DepthAttachmentToString(const DepthAttachment &depth)
Definition formats.cc:144
std::string ColorAttachmentToString(const ColorAttachment &color)
Definition formats.cc:137
PrimitiveType
Decides how backend draws pixels based on input vertices.
Definition formats.h:529
@ kPoint
Draws a point at each input vertex.
float Scalar
Definition scalar.h:19
SamplerAddressMode
Definition formats.h:618
@ kDecal
decal sampling mode is only supported on devices that pass the Capabilities.SupportsDecalSamplerAddre...
constexpr bool IsDepthWritable(PixelFormat format)
Definition formats.h:271
std::string StencilAttachmentToString(const StencilAttachment &stencil)
Definition formats.cc:151
std::string TextureUsageMaskToString(TextureUsageMask mask)
Definition formats.cc:95
StorageMode
Specified where the allocation resides and how it is used.
Definition formats.h:32
std::string AttachmentToString(const Attachment &attachment)
Definition formats.cc:118
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition formats.h:99
CompareFunction
Definition formats.h:804
@ kEqual
Comparison test passes if new_value == current_value.
@ kLessEqual
Comparison test passes if new_value <= current_value.
@ kGreaterEqual
Comparison test passes if new_value >= current_value.
@ kAlways
Comparison test passes always passes.
@ kLess
Comparison test passes if new_value < current_value.
@ kGreater
Comparison test passes if new_value > current_value.
@ kNotEqual
Comparison test passes if new_value != current_value.
@ kNever
Comparison test never passes.
constexpr const char * LoadActionToString(LoadAction action)
Definition formats.h:403
constexpr const char * StoreActionToString(StoreAction action)
Definition formats.h:414
MipFilter
Options for selecting and filtering between mipmap levels.
Definition formats.h:602
@ kBase
The texture is sampled as if it only had a single mipmap level.
StencilOperation
Definition formats.h:823
@ kDecrementWrap
Decrement the current stencil value by 1. If at zero, set to maximum.
@ kSetToReferenceValue
Reset the stencil value to the reference value.
@ kDecrementClamp
Decrement the current stencil value by 1. Clamp it to zero.
@ kIncrementClamp
Increment the current stencil value by 1. Clamp it to the maximum.
@ kIncrementWrap
Increment the current stencil value by 1. If at maximum, set to zero.
@ kInvert
Perform a logical bitwise invert on the current stencil value.
@ kKeep
Don't modify the current stencil value.
CompressedTextureFamily
The family of a block-compressed pixel format. GPUs support compressed formats on a per-family basis,...
Definition formats.h:146
@ kASTCHDR
ASTC HDR. A separate device feature from ASTC LDR.
@ kBC
S3TC, RGTC, and BPTC (BC1 through BC7). Desktop GPUs.
@ kETC2
ETC2 and EAC. Mobile, OpenGL ES 3.0, and WebGL2.
@ kASTC
ASTC LDR. Modern mobile and some desktop.
WindingOrder
Definition formats.h:22
constexpr size_t CompressedBlockWidthForPixelFormat(PixelFormat format)
The width, in texels, of one compression block. Uncompressed formats report 1.
Definition formats.h:217
constexpr size_t BytesForTextureRegion(PixelFormat format, int64_t width, int64_t height)
The number of bytes required to store a width x height texel region in format. Block-compressed forma...
Definition formats.h:727
constexpr bool IsStencilWritable(PixelFormat format)
Definition formats.h:281
constexpr size_t BytesPerRowForTextureWidth(PixelFormat format, int64_t width)
The number of bytes in a single row of texel blocks for a texture of the given width in format.
Definition formats.h:741
constexpr size_t BytesPerBlockForPixelFormat(PixelFormat format)
The number of bytes used to store one block of format. For uncompressed formats a block is a single p...
Definition formats.h:697
constexpr CompressedTextureFamily CompressedTextureFamilyForFormat(PixelFormat format)
The compression family that format belongs to. Only valid for formats where IsCompressed is true.
Definition formats.h:185
constexpr const char * TextureTypeToString(TextureType type)
Definition formats.h:457
constexpr const char * StorageModeToString(StorageMode mode)
Definition formats.h:60
constexpr bool IsMultisampleCapable(TextureType type)
Definition formats.h:471
MinMagFilter
Describes how the texture should be sampled when the texture is being shrunk (minified) or expanded (...
Definition formats.h:592
@ kNearest
Select nearest to the sample point. Most widely supported.
constexpr bool IsCompressed(PixelFormat format)
Whether format is a block-compressed format.
Definition formats.h:158
ColorWriteMaskBits
Definition formats.h:631
constexpr const char * TextureUsageToString(TextureUsage usage)
Definition formats.h:498
Mask< TextureUsage > TextureUsageMask
Definition formats.h:496
constexpr const char * PixelFormatToString(PixelFormat format)
Definition formats.h:292
BlendOperation
Definition formats.h:384
constexpr bool CanDiscardAttachmentWhenDone(StoreAction action)
Definition formats.h:438
Definition ref_ptr.h:261
impeller::ShaderType type
int32_t height
int32_t width
std::shared_ptr< Texture > resolve_texture
Definition formats.h:910
bool IsValid() const
Definition formats.cc:26
LoadAction load_action
Definition formats.h:911
std::shared_ptr< Texture > texture
Definition formats.h:909
StoreAction store_action
Definition formats.h:912
Describe the color attachment that will be used with this pipeline.
Definition formats.h:770
constexpr size_t Hash() const
Definition formats.h:796
constexpr bool operator==(const ColorAttachmentDescriptor &o) const
Definition formats.h:784
static constexpr Color BlackTransparent()
Definition color.h:275
constexpr bool operator==(const DepthAttachmentDescriptor &o) const
Definition formats.h:852
constexpr size_t GetHash() const
Definition formats.h:857
constexpr bool operator==(const DepthRange &other) const
Definition formats.h:575
constexpr bool operator==(const StencilAttachmentDescriptor &o) const
Definition formats.h:894
constexpr size_t GetHash() const
Definition formats.h:902
constexpr bool operator==(const Viewport &other) const
Definition formats.h:584
DepthRange depth_range
Definition formats.h:582
constexpr std::size_t operator()(const impeller::DepthAttachmentDescriptor &des) const
Definition formats.h:949
constexpr std::size_t operator()(const impeller::StencilAttachmentDescriptor &des) const
Definition formats.h:957