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 | #pragma once |
6 | |
7 | #include <cstdint> |
8 | #include <functional> |
9 | #include <memory> |
10 | #include <string> |
11 | #include <type_traits> |
12 | |
13 | #include "flutter/fml/hash_combine.h" |
14 | #include "flutter/fml/logging.h" |
15 | #include "flutter/fml/macros.h" |
16 | #include "impeller/geometry/color.h" |
17 | #include "impeller/geometry/rect.h" |
18 | #include "impeller/geometry/scalar.h" |
19 | |
20 | namespace impeller { |
21 | |
22 | class Texture; |
23 | |
24 | //------------------------------------------------------------------------------ |
25 | /// @brief Specified where the allocation resides and how it is used. |
26 | /// |
27 | enum class StorageMode { |
28 | //---------------------------------------------------------------------------- |
29 | /// Allocations can be mapped onto the hosts address space and also be used by |
30 | /// the device. |
31 | /// |
32 | kHostVisible, |
33 | //---------------------------------------------------------------------------- |
34 | /// Allocations can only be used by the device. This location is optimal for |
35 | /// use by the device. If the host needs to access these allocations, the |
36 | /// transfer queue must be used to transfer this allocation onto the a host |
37 | /// visible buffer. |
38 | /// |
39 | kDevicePrivate, |
40 | //---------------------------------------------------------------------------- |
41 | /// Used by the device for temporary render targets. These allocations cannot |
42 | /// be transferred from and to other allocations using the transfer queue. |
43 | /// Render pass cannot initialize the contents of these buffers using load and |
44 | /// store actions. |
45 | /// |
46 | /// These allocations reside in tile memory which has higher bandwidth, lower |
47 | /// latency and lower power consumption. The total device memory usage is |
48 | /// also lower as a separate allocation does not need to be created in |
49 | /// device memory. Prefer using these allocations for intermediates like depth |
50 | /// and stencil buffers. |
51 | /// |
52 | kDeviceTransient, |
53 | }; |
54 | |
55 | constexpr const char* StorageModeToString(StorageMode mode) { |
56 | switch (mode) { |
57 | case StorageMode::kHostVisible: |
58 | return "HostVisible"; |
59 | case StorageMode::kDevicePrivate: |
60 | return "DevicePrivate"; |
61 | case StorageMode::kDeviceTransient: |
62 | return "DeviceTransient"; |
63 | } |
64 | FML_UNREACHABLE(); |
65 | } |
66 | |
67 | //------------------------------------------------------------------------------ |
68 | /// @brief The Pixel formats supported by Impeller. The naming convention |
69 | /// denotes the usage of the component, the bit width of that |
70 | /// component, and then one or more qualifiers to its |
71 | /// interpretation. |
72 | /// |
73 | /// For instance, `kR8G8B8A8UNormIntSRGB` is a 32 bits-per-pixel |
74 | /// format ordered in RGBA with 8 bits per component with each |
75 | /// component expressed as an unsigned normalized integer and a |
76 | /// conversion from sRGB to linear color space. |
77 | /// |
78 | /// Key: |
79 | /// R -> Red Component |
80 | /// G -> Green Component |
81 | /// B -> Blue Component |
82 | /// D -> Depth Component |
83 | /// S -> Stencil Component |
84 | /// U -> Unsigned (Lack of this denotes a signed component) |
85 | /// Norm -> Normalized |
86 | /// SRGB -> sRGB to linear interpretation |
87 | /// |
88 | /// While the effective bit width of the pixel can be determined by |
89 | /// adding up the widths of each component, only the non-esoteric |
90 | /// formats are tightly packed. Do not assume tight packing for the |
91 | /// esoteric formats and use blit passes to convert to a |
92 | /// non-esoteric pass. |
93 | /// |
94 | enum class PixelFormat { |
95 | kUnknown, |
96 | kA8UNormInt, |
97 | kR8UNormInt, |
98 | kR8G8UNormInt, |
99 | kR8G8B8A8UNormInt, |
100 | kR8G8B8A8UNormIntSRGB, |
101 | kB8G8R8A8UNormInt, |
102 | kB8G8R8A8UNormIntSRGB, |
103 | kR32G32B32A32Float, |
104 | kR16G16B16A16Float, |
105 | kB10G10R10XR, |
106 | kB10G10R10XRSRGB, |
107 | kB10G10R10A10XR, |
108 | // Depth and stencil formats. |
109 | kS8UInt, |
110 | kD32FloatS8UInt, |
111 | }; |
112 | |
113 | constexpr const char* PixelFormatToString(PixelFormat format) { |
114 | switch (format) { |
115 | case PixelFormat::kUnknown: |
116 | return "Unknown"; |
117 | case PixelFormat::kA8UNormInt: |
118 | return "A8UNormInt"; |
119 | case PixelFormat::kR8UNormInt: |
120 | return "R8UNormInt"; |
121 | case PixelFormat::kR8G8UNormInt: |
122 | return "R8G8UNormInt"; |
123 | case PixelFormat::kR8G8B8A8UNormInt: |
124 | return "R8G8B8A8UNormInt"; |
125 | case PixelFormat::kR8G8B8A8UNormIntSRGB: |
126 | return "R8G8B8A8UNormIntSRGB"; |
127 | case PixelFormat::kB8G8R8A8UNormInt: |
128 | return "B8G8R8A8UNormInt"; |
129 | case PixelFormat::kB8G8R8A8UNormIntSRGB: |
130 | return "B8G8R8A8UNormIntSRGB"; |
131 | case PixelFormat::kR32G32B32A32Float: |
132 | return "R32G32B32A32Float"; |
133 | case PixelFormat::kR16G16B16A16Float: |
134 | return "R16G16B16A16Float"; |
135 | case PixelFormat::kB10G10R10XR: |
136 | return "B10G10R10XR"; |
137 | case PixelFormat::kB10G10R10XRSRGB: |
138 | return "B10G10R10XRSRGB"; |
139 | case PixelFormat::kB10G10R10A10XR: |
140 | return "B10G10R10A10XR"; |
141 | case PixelFormat::kS8UInt: |
142 | return "S8UInt"; |
143 | case PixelFormat::kD32FloatS8UInt: |
144 | return "D32FloatS8UInt"; |
145 | } |
146 | FML_UNREACHABLE(); |
147 | } |
148 | |
149 | enum class BlendFactor { |
150 | kZero, |
151 | kOne, |
152 | kSourceColor, |
153 | kOneMinusSourceColor, |
154 | kSourceAlpha, |
155 | kOneMinusSourceAlpha, |
156 | kDestinationColor, |
157 | kOneMinusDestinationColor, |
158 | kDestinationAlpha, |
159 | kOneMinusDestinationAlpha, |
160 | kSourceAlphaSaturated, |
161 | kBlendColor, |
162 | kOneMinusBlendColor, |
163 | kBlendAlpha, |
164 | kOneMinusBlendAlpha, |
165 | }; |
166 | |
167 | enum class BlendOperation { |
168 | kAdd, |
169 | kSubtract, |
170 | kReverseSubtract, |
171 | }; |
172 | |
173 | enum class LoadAction { |
174 | kDontCare, |
175 | kLoad, |
176 | kClear, |
177 | }; |
178 | |
179 | enum class StoreAction { |
180 | kDontCare, |
181 | kStore, |
182 | kMultisampleResolve, |
183 | kStoreAndMultisampleResolve, |
184 | }; |
185 | |
186 | constexpr const char* LoadActionToString(LoadAction action) { |
187 | switch (action) { |
188 | case LoadAction::kDontCare: |
189 | return "DontCare"; |
190 | case LoadAction::kLoad: |
191 | return "Load"; |
192 | case LoadAction::kClear: |
193 | return "Clear"; |
194 | } |
195 | } |
196 | |
197 | constexpr const char* StoreActionToString(StoreAction action) { |
198 | switch (action) { |
199 | case StoreAction::kDontCare: |
200 | return "DontCare"; |
201 | case StoreAction::kStore: |
202 | return "Store"; |
203 | case StoreAction::kMultisampleResolve: |
204 | return "MultisampleResolve"; |
205 | case StoreAction::kStoreAndMultisampleResolve: |
206 | return "StoreAndMultisampleResolve"; |
207 | } |
208 | } |
209 | |
210 | constexpr bool CanClearAttachment(LoadAction action) { |
211 | switch (action) { |
212 | case LoadAction::kLoad: |
213 | return false; |
214 | case LoadAction::kDontCare: |
215 | case LoadAction::kClear: |
216 | return true; |
217 | } |
218 | FML_UNREACHABLE(); |
219 | } |
220 | |
221 | constexpr bool CanDiscardAttachmentWhenDone(StoreAction action) { |
222 | switch (action) { |
223 | case StoreAction::kStore: |
224 | case StoreAction::kStoreAndMultisampleResolve: |
225 | return false; |
226 | case StoreAction::kDontCare: |
227 | case StoreAction::kMultisampleResolve: |
228 | return true; |
229 | } |
230 | FML_UNREACHABLE(); |
231 | } |
232 | |
233 | enum class TextureType { |
234 | kTexture2D, |
235 | kTexture2DMultisample, |
236 | kTextureCube, |
237 | }; |
238 | |
239 | constexpr const char* TextureTypeToString(TextureType type) { |
240 | switch (type) { |
241 | case TextureType::kTexture2D: |
242 | return "Texture2D"; |
243 | case TextureType::kTexture2DMultisample: |
244 | return "Texture2DMultisample"; |
245 | case TextureType::kTextureCube: |
246 | return "TextureCube"; |
247 | } |
248 | FML_UNREACHABLE(); |
249 | } |
250 | |
251 | constexpr bool IsMultisampleCapable(TextureType type) { |
252 | switch (type) { |
253 | case TextureType::kTexture2D: |
254 | case TextureType::kTextureCube: |
255 | return false; |
256 | case TextureType::kTexture2DMultisample: |
257 | return true; |
258 | } |
259 | return false; |
260 | } |
261 | |
262 | enum class SampleCount { |
263 | kCount1 = 1, |
264 | kCount4 = 4, |
265 | }; |
266 | |
267 | using TextureUsageMask = uint64_t; |
268 | |
269 | enum class TextureUsage : TextureUsageMask { |
270 | kUnknown = 0, |
271 | kShaderRead = 1 << 0, |
272 | kShaderWrite = 1 << 1, |
273 | kRenderTarget = 1 << 2, |
274 | }; |
275 | |
276 | constexpr bool TextureUsageIsRenderTarget(TextureUsageMask mask) { |
277 | return static_cast<TextureUsageMask>(TextureUsage::kRenderTarget) & mask; |
278 | } |
279 | |
280 | constexpr const char* TextureUsageToString(TextureUsage usage) { |
281 | switch (usage) { |
282 | case TextureUsage::kUnknown: |
283 | return "Unknown"; |
284 | case TextureUsage::kShaderRead: |
285 | return "ShaderRead"; |
286 | case TextureUsage::kShaderWrite: |
287 | return "ShaderWrite"; |
288 | case TextureUsage::kRenderTarget: |
289 | return "RenderTarget"; |
290 | } |
291 | FML_UNREACHABLE(); |
292 | } |
293 | |
294 | std::string TextureUsageMaskToString(TextureUsageMask mask); |
295 | |
296 | enum class TextureIntent { |
297 | kUploadFromHost, |
298 | kRenderToTexture, |
299 | }; |
300 | |
301 | enum class CullMode { |
302 | kNone, |
303 | kFrontFace, |
304 | kBackFace, |
305 | }; |
306 | |
307 | enum class IndexType { |
308 | kUnknown, |
309 | k16bit, |
310 | k32bit, |
311 | /// Does not use the index buffer. |
312 | kNone, |
313 | }; |
314 | |
315 | enum class PrimitiveType { |
316 | kTriangle, |
317 | kTriangleStrip, |
318 | kLine, |
319 | kLineStrip, |
320 | kPoint, |
321 | // Triangle fans are implementation dependent and need extra extensions |
322 | // checks. Hence, they are not supported here. |
323 | }; |
324 | |
325 | enum class PolygonMode { |
326 | kFill, |
327 | kLine, |
328 | }; |
329 | |
330 | struct DepthRange { |
331 | Scalar z_near = 0.0; |
332 | Scalar z_far = 1.0; |
333 | |
334 | constexpr bool operator==(const DepthRange& other) const { |
335 | return z_near == other.z_near && z_far == other.z_far; |
336 | } |
337 | }; |
338 | |
339 | struct Viewport { |
340 | Rect rect; |
341 | DepthRange depth_range; |
342 | |
343 | constexpr bool operator==(const Viewport& other) const { |
344 | return rect == other.rect && depth_range == other.depth_range; |
345 | } |
346 | }; |
347 | |
348 | enum class MinMagFilter { |
349 | /// Select nearest to the sample point. Most widely supported. |
350 | kNearest, |
351 | /// Select two points and linearly interpolate between them. Some formats |
352 | /// may not support this. |
353 | kLinear, |
354 | }; |
355 | |
356 | enum class MipFilter { |
357 | /// Sample from the nearest mip level. |
358 | kNearest, |
359 | /// Sample from the two nearest mip levels and linearly interpolate between |
360 | /// them. |
361 | kLinear, |
362 | }; |
363 | |
364 | enum class SamplerAddressMode { |
365 | kClampToEdge, |
366 | kRepeat, |
367 | kMirror, |
368 | // More modes are almost always supported but they are usually behind |
369 | // extensions checks. The ones current in these structs are safe (always |
370 | // supported) defaults. |
371 | |
372 | /// @brief decal sampling mode is only supported on devices that pass |
373 | /// the Capabilities.SupportsDecalTileMode check. |
374 | kDecal, |
375 | }; |
376 | |
377 | enum class ColorWriteMask : uint64_t { |
378 | kNone = 0, |
379 | kRed = 1 << 0, |
380 | kGreen = 1 << 1, |
381 | kBlue = 1 << 2, |
382 | kAlpha = 1 << 3, |
383 | kAll = kRed | kGreen | kBlue | kAlpha, |
384 | }; |
385 | |
386 | constexpr size_t BytesPerPixelForPixelFormat(PixelFormat format) { |
387 | switch (format) { |
388 | case PixelFormat::kUnknown: |
389 | return 0u; |
390 | case PixelFormat::kA8UNormInt: |
391 | case PixelFormat::kR8UNormInt: |
392 | case PixelFormat::kS8UInt: |
393 | return 1u; |
394 | case PixelFormat::kR8G8UNormInt: |
395 | return 2u; |
396 | case PixelFormat::kR8G8B8A8UNormInt: |
397 | case PixelFormat::kR8G8B8A8UNormIntSRGB: |
398 | case PixelFormat::kB8G8R8A8UNormInt: |
399 | case PixelFormat::kB8G8R8A8UNormIntSRGB: |
400 | case PixelFormat::kB10G10R10XRSRGB: |
401 | case PixelFormat::kB10G10R10XR: |
402 | return 4u; |
403 | case PixelFormat::kD32FloatS8UInt: |
404 | return 5u; |
405 | case PixelFormat::kR16G16B16A16Float: |
406 | case PixelFormat::kB10G10R10A10XR: |
407 | return 8u; |
408 | case PixelFormat::kR32G32B32A32Float: |
409 | return 16u; |
410 | } |
411 | return 0u; |
412 | } |
413 | |
414 | //------------------------------------------------------------------------------ |
415 | /// @brief Describe the color attachment that will be used with this |
416 | /// pipeline. |
417 | /// |
418 | /// Blending at specific color attachments follows the pseudo-code: |
419 | /// ``` |
420 | /// if (blending_enabled) { |
421 | /// final_color.rgb = (src_color_blend_factor * new_color.rgb) |
422 | /// <color_blend_op> |
423 | /// (dst_color_blend_factor * old_color.rgb); |
424 | /// final_color.a = (src_alpha_blend_factor * new_color.a) |
425 | /// <alpha_blend_op> |
426 | /// (dst_alpha_blend_factor * old_color.a); |
427 | /// } else { |
428 | /// final_color = new_color; |
429 | /// } |
430 | /// // IMPORTANT: The write mask is applied irrespective of whether |
431 | /// // blending_enabled is set. |
432 | /// final_color = final_color & write_mask; |
433 | /// ``` |
434 | /// |
435 | /// The default blend mode is 1 - source alpha. |
436 | struct ColorAttachmentDescriptor { |
437 | PixelFormat format = PixelFormat::kUnknown; |
438 | bool blending_enabled = false; |
439 | |
440 | BlendFactor src_color_blend_factor = BlendFactor::kSourceAlpha; |
441 | BlendOperation color_blend_op = BlendOperation::kAdd; |
442 | BlendFactor dst_color_blend_factor = BlendFactor::kOneMinusSourceAlpha; |
443 | |
444 | BlendFactor src_alpha_blend_factor = BlendFactor::kSourceAlpha; |
445 | BlendOperation alpha_blend_op = BlendOperation::kAdd; |
446 | BlendFactor dst_alpha_blend_factor = BlendFactor::kOneMinusSourceAlpha; |
447 | |
448 | std::underlying_type_t<ColorWriteMask> write_mask = |
449 | static_cast<uint64_t>(ColorWriteMask::kAll); |
450 | |
451 | constexpr bool operator==(const ColorAttachmentDescriptor& o) const { |
452 | return format == o.format && // |
453 | blending_enabled == o.blending_enabled && // |
454 | src_color_blend_factor == o.src_color_blend_factor && // |
455 | color_blend_op == o.color_blend_op && // |
456 | dst_color_blend_factor == o.dst_color_blend_factor && // |
457 | src_alpha_blend_factor == o.src_alpha_blend_factor && // |
458 | alpha_blend_op == o.alpha_blend_op && // |
459 | dst_alpha_blend_factor == o.dst_alpha_blend_factor && // |
460 | write_mask == o.write_mask; |
461 | } |
462 | |
463 | constexpr size_t Hash() const { |
464 | return fml::HashCombine(args: format, args: blending_enabled, args: src_color_blend_factor, |
465 | args: color_blend_op, args: dst_color_blend_factor, |
466 | args: src_alpha_blend_factor, args: alpha_blend_op, |
467 | args: dst_alpha_blend_factor, args: write_mask); |
468 | } |
469 | }; |
470 | |
471 | enum class CompareFunction { |
472 | /// Comparison test never passes. |
473 | kNever, |
474 | /// Comparison test passes always passes. |
475 | kAlways, |
476 | /// Comparison test passes if new_value < current_value. |
477 | kLess, |
478 | /// Comparison test passes if new_value == current_value. |
479 | kEqual, |
480 | /// Comparison test passes if new_value <= current_value. |
481 | kLessEqual, |
482 | /// Comparison test passes if new_value > current_value. |
483 | kGreater, |
484 | /// Comparison test passes if new_value != current_value. |
485 | kNotEqual, |
486 | /// Comparison test passes if new_value >= current_value. |
487 | kGreaterEqual, |
488 | }; |
489 | |
490 | enum class StencilOperation { |
491 | /// Don't modify the current stencil value. |
492 | kKeep, |
493 | /// Reset the stencil value to zero. |
494 | kZero, |
495 | /// Reset the stencil value to the reference value. |
496 | kSetToReferenceValue, |
497 | /// Increment the current stencil value by 1. Clamp it to the maximum. |
498 | kIncrementClamp, |
499 | /// Decrement the current stencil value by 1. Clamp it to zero. |
500 | kDecrementClamp, |
501 | /// Perform a logical bitwise invert on the current stencil value. |
502 | kInvert, |
503 | /// Increment the current stencil value by 1. If at maximum, set to zero. |
504 | kIncrementWrap, |
505 | /// Decrement the current stencil value by 1. If at zero, set to maximum. |
506 | kDecrementWrap, |
507 | }; |
508 | |
509 | struct DepthAttachmentDescriptor { |
510 | //---------------------------------------------------------------------------- |
511 | /// Indicates how to compare the value with that in the depth buffer. |
512 | /// |
513 | CompareFunction depth_compare = CompareFunction::kAlways; |
514 | //---------------------------------------------------------------------------- |
515 | /// Indicates when writes must be performed to the depth buffer. |
516 | /// |
517 | bool depth_write_enabled = false; |
518 | |
519 | constexpr bool operator==(const DepthAttachmentDescriptor& o) const { |
520 | return depth_compare == o.depth_compare && |
521 | depth_write_enabled == o.depth_write_enabled; |
522 | } |
523 | |
524 | constexpr size_t GetHash() const { |
525 | return fml::HashCombine(args: depth_compare, args: depth_write_enabled); |
526 | } |
527 | }; |
528 | |
529 | struct StencilAttachmentDescriptor { |
530 | //---------------------------------------------------------------------------- |
531 | /// Indicates the operation to perform between the reference value and the |
532 | /// value in the stencil buffer. Both values have the read_mask applied to |
533 | /// them before performing this operation. |
534 | /// |
535 | CompareFunction stencil_compare = CompareFunction::kAlways; |
536 | //---------------------------------------------------------------------------- |
537 | /// Indicates what to do when the stencil test has failed. |
538 | /// |
539 | StencilOperation stencil_failure = StencilOperation::kKeep; |
540 | //---------------------------------------------------------------------------- |
541 | /// Indicates what to do when the stencil test passes but the depth test |
542 | /// fails. |
543 | /// |
544 | StencilOperation depth_failure = StencilOperation::kKeep; |
545 | //---------------------------------------------------------------------------- |
546 | /// Indicates what to do when both the stencil and depth tests pass. |
547 | /// |
548 | StencilOperation depth_stencil_pass = StencilOperation::kKeep; |
549 | |
550 | //---------------------------------------------------------------------------- |
551 | /// The mask applied to the reference and stencil buffer values before |
552 | /// performing the stencil_compare operation. |
553 | /// |
554 | uint32_t read_mask = ~0; |
555 | //---------------------------------------------------------------------------- |
556 | /// The mask applied to the new stencil value before it is written into the |
557 | /// stencil buffer. |
558 | /// |
559 | uint32_t write_mask = ~0; |
560 | |
561 | constexpr bool operator==(const StencilAttachmentDescriptor& o) const { |
562 | return stencil_compare == o.stencil_compare && |
563 | stencil_failure == o.stencil_failure && |
564 | depth_failure == o.depth_failure && |
565 | depth_stencil_pass == o.depth_stencil_pass && |
566 | read_mask == o.read_mask && write_mask == o.write_mask; |
567 | } |
568 | |
569 | constexpr size_t GetHash() const { |
570 | return fml::HashCombine(args: stencil_compare, args: stencil_failure, args: depth_failure, |
571 | args: depth_stencil_pass, args: read_mask, args: write_mask); |
572 | } |
573 | }; |
574 | |
575 | struct Attachment { |
576 | std::shared_ptr<Texture> texture; |
577 | std::shared_ptr<Texture> resolve_texture; |
578 | LoadAction load_action = LoadAction::kDontCare; |
579 | StoreAction store_action = StoreAction::kStore; |
580 | |
581 | bool IsValid() const; |
582 | }; |
583 | |
584 | struct ColorAttachment : public Attachment { |
585 | Color clear_color = Color::BlackTransparent(); |
586 | }; |
587 | |
588 | struct DepthAttachment : public Attachment { |
589 | double clear_depth = 0.0; |
590 | }; |
591 | |
592 | struct StencilAttachment : public Attachment { |
593 | uint32_t clear_stencil = 0; |
594 | }; |
595 | |
596 | std::string AttachmentToString(const Attachment& attachment); |
597 | |
598 | std::string ColorAttachmentToString(const ColorAttachment& color); |
599 | |
600 | std::string DepthAttachmentToString(const DepthAttachment& depth); |
601 | |
602 | std::string StencilAttachmentToString(const StencilAttachment& stencil); |
603 | |
604 | } // namespace impeller |
605 | |
606 | namespace std { |
607 | |
608 | template <> |
609 | struct hash<impeller::DepthAttachmentDescriptor> { |
610 | constexpr std::size_t operator()( |
611 | const impeller::DepthAttachmentDescriptor& des) const { |
612 | return des.GetHash(); |
613 | } |
614 | }; |
615 | |
616 | template <> |
617 | struct hash<impeller::StencilAttachmentDescriptor> { |
618 | constexpr std::size_t operator()( |
619 | const impeller::StencilAttachmentDescriptor& des) const { |
620 | return des.GetHash(); |
621 | } |
622 | }; |
623 | |
624 | } // namespace std |
625 |
Definitions
- StorageMode
- StorageModeToString
- PixelFormat
- PixelFormatToString
- BlendFactor
- BlendOperation
- LoadAction
- StoreAction
- LoadActionToString
- StoreActionToString
- CanClearAttachment
- CanDiscardAttachmentWhenDone
- TextureType
- TextureTypeToString
- IsMultisampleCapable
- SampleCount
- TextureUsage
- TextureUsageIsRenderTarget
- TextureUsageToString
- TextureIntent
- CullMode
- IndexType
- PrimitiveType
- PolygonMode
- DepthRange
- operator==
- Viewport
- operator==
- MinMagFilter
- MipFilter
- SamplerAddressMode
- ColorWriteMask
- BytesPerPixelForPixelFormat
- ColorAttachmentDescriptor
- operator==
- Hash
- CompareFunction
- StencilOperation
- DepthAttachmentDescriptor
- operator==
- GetHash
- StencilAttachmentDescriptor
- operator==
- GetHash
- Attachment
- ColorAttachment
- DepthAttachment
- StencilAttachment
- hash
- operator()
- hash
Learn more about Flutter for embedded and desktop on industrialflutter.com