-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] support half precision uniforms and half precision samplers #40590
Changes from 4 commits
02ccd58
3c00839
43ff491
68b1009
b6e6f81
d739b58
f1919b4
a98fa07
7dca490
9599b62
4bdc197
a8b80ed
8e9892b
1bce547
22a0bd1
c802c7c
251564b
51d7bb7
9001fe1
11f0c9f
6998f76
205db32
736a3e5
0af6ab9
31cf48a
c9ffbc5
b2996a8
2f1f5c3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -534,6 +534,11 @@ static std::optional<KnownType> ReadKnownScalarType( | |
| .name = "Scalar", | ||
| .byte_size = sizeof(Scalar), | ||
| }; | ||
| case spirv_cross::SPIRType::BaseType::Half: | ||
| return KnownType{ | ||
| .name = "Half", | ||
| .byte_size = sizeof(Half), | ||
| }; | ||
| case spirv_cross::SPIRType::BaseType::UInt: | ||
| return KnownType{ | ||
| .name = "uint32_t", | ||
|
|
@@ -767,6 +772,75 @@ std::vector<StructMember> Reflector::ReadStructMembers( | |
| continue; | ||
| } | ||
|
|
||
| // Tightly packed half Point (vec2). | ||
| if (member.basetype == spirv_cross::SPIRType::BaseType::Half && // | ||
| member.width == sizeof(float) * 4 && // | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you double check this? The member width doesn't make sense for half base types. I may be misunderstanding.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah, this was a hack I left in. Should be |
||
| member.columns == 1 && // | ||
| member.vecsize == 2 // | ||
| ) { | ||
| uint32_t stride = | ||
| GetArrayStride<sizeof(HalfPoint)>(struct_type, member, i); | ||
| uint32_t element_padding = stride - sizeof(HalfPoint); | ||
| result.emplace_back(StructMember{ | ||
| "HalfPoint", // type | ||
| BaseTypeToString(member.basetype), // basetype | ||
| GetMemberNameAtIndex(struct_type, i), // name | ||
| struct_member_offset, // offset | ||
| sizeof(HalfPoint), // size | ||
| stride * array_elements.value_or(1), // byte_length | ||
| array_elements, // array_elements | ||
| element_padding, // element_padding | ||
| }); | ||
| current_byte_offset += stride * array_elements.value_or(1); | ||
| continue; | ||
| } | ||
|
|
||
| // Tightly packed Half Float Vector3. | ||
| if (member.basetype == spirv_cross::SPIRType::BaseType::Half && // | ||
| member.width == sizeof(float) * 4 && // | ||
| member.columns == 1 && // | ||
| member.vecsize == 3 // | ||
| ) { | ||
| uint32_t stride = | ||
| GetArrayStride<sizeof(HalfVector3)>(struct_type, member, i); | ||
| uint32_t element_padding = stride - sizeof(HalfVector3); | ||
| result.emplace_back(StructMember{ | ||
| "HalfVector3", // type | ||
| BaseTypeToString(member.basetype), // basetype | ||
| GetMemberNameAtIndex(struct_type, i), // name | ||
| struct_member_offset, // offset | ||
| sizeof(HalfVector3), // size | ||
| stride * array_elements.value_or(1), // byte_length | ||
| array_elements, // array_elements | ||
| element_padding, // element_padding | ||
| }); | ||
| current_byte_offset += stride * array_elements.value_or(1); | ||
| continue; | ||
| } | ||
|
|
||
| // Tightly packed Half Float Vector4. | ||
| if (member.basetype == spirv_cross::SPIRType::BaseType::Half && // | ||
| member.width == sizeof(float) * 4 && // | ||
| member.columns == 1 && // | ||
| member.vecsize == 4 // | ||
| ) { | ||
| uint32_t stride = | ||
| GetArrayStride<sizeof(HalfVector4)>(struct_type, member, i); | ||
| uint32_t element_padding = stride - sizeof(HalfVector4); | ||
| result.emplace_back(StructMember{ | ||
| "HalfVector4", // type | ||
| BaseTypeToString(member.basetype), // basetype | ||
| GetMemberNameAtIndex(struct_type, i), // name | ||
| struct_member_offset, // offset | ||
| sizeof(HalfVector4), // size | ||
| stride * array_elements.value_or(1), // byte_length | ||
| array_elements, // array_elements | ||
| element_padding, // element_padding | ||
| }); | ||
| current_byte_offset += stride * array_elements.value_or(1); | ||
| continue; | ||
| } | ||
|
|
||
| // Other isolated scalars (like bool, int, float/Scalar, etc..). | ||
| { | ||
| auto maybe_known_type = ReadKnownScalarType(member.basetype); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,11 +5,11 @@ | |
| #include <impeller/types.glsl> | ||
|
|
||
| uniform FragInfo { | ||
| vec4 color; | ||
| f16vec4 color; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't this require
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It does not, I'm not actually using a f16vec4 on glsl, here is the compiled shader:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh - but this is all in types.glsl too |
||
| } | ||
| frag_info; | ||
|
|
||
| out vec4 frag_color; | ||
| out f16vec4 frag_color; | ||
|
|
||
| void main() { | ||
| frag_color = frag_info.color; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| #include "scalar.h" | ||
|
|
||
| namespace impeller { | ||
|
|
||
| uint16_t ScalarToHalf(Scalar f) { | ||
| // __fp16 foo = f; | ||
|
jonahwilliams marked this conversation as resolved.
Outdated
|
||
| // return foo; | ||
|
|
||
| uint32_t x = *reinterpret_cast<const uint32_t*>(&f); | ||
| uint32_t sign = (uint16_t)(x >> 31); | ||
| uint32_t mantissa; | ||
| uint32_t exp; | ||
| uint16_t hf; | ||
|
|
||
| mantissa = x & ((1 << 23) - 1); | ||
| exp = x & (0xFF << 23); | ||
| if (exp >= 0x47800000) { | ||
| // check if the original number is a NaN | ||
| if (mantissa && (exp == (0xFF << 23))) { | ||
| // single precision NaN | ||
| mantissa = (1 << 23) - 1; | ||
| } else { | ||
| // half-float will be Inf | ||
| mantissa = 0; | ||
| } | ||
| hf = (((uint16_t)sign) << 15) | (uint16_t)((0x1F << 10)) | | ||
| (uint16_t)(mantissa >> 13); | ||
| } | ||
| // check if exponent is <= -15 | ||
| else if (exp <= 0x38000000) { | ||
| hf = 0; // too small to be represented | ||
| } else { | ||
| hf = (((uint16_t)sign) << 15) | (uint16_t)((exp - 0x38000000) >> 13) | | ||
| (uint16_t)(mantissa >> 13); | ||
| } | ||
| return hf; | ||
| } | ||
|
|
||
| } // namespace impeller | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| #pragma once | ||
|
|
||
| #include <cfloat> | ||
| #include <cstdint> | ||
| #include <type_traits> | ||
| #include <valarray> | ||
|
|
||
|
|
@@ -13,6 +14,7 @@ | |
| namespace impeller { | ||
|
|
||
| using Scalar = float; | ||
| using Half = uint16_t; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How is this different from the _Float16 C11 extension? I also see
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TIL |
||
|
|
||
| template <class T, class = std::enable_if_t<std::is_arithmetic_v<T>>> | ||
| constexpr T Absolute(const T& val) { | ||
|
|
@@ -52,4 +54,11 @@ struct Degrees { | |
| }; | ||
| }; | ||
|
|
||
| /// @brief Convert a scalar to a half precision float. | ||
| /// | ||
| /// Can express numbers in the range of 2^-14 to 65504. | ||
| /// Adapted from | ||
| /// https://developer.android.com/games/optimize/vertex-data-management . | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should document the behavior of this and how it handles precision loss, and add some tests that assert it. Specifically:
|
||
| Half ScalarToHalf(Scalar f); | ||
|
|
||
| } // namespace impeller | ||
Uh oh!
There was an error while loading. Please reload this page.