1 // Copyright 2017 The Dawn 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 #include "common/Math.h"
16
17 #include "common/Assert.h"
18
19 #include <algorithm>
20 #include <cmath>
21
22 #if defined(DAWN_COMPILER_MSVC)
23 # include <intrin.h>
24 #endif
25
ScanForward(uint32_t bits)26 uint32_t ScanForward(uint32_t bits) {
27 ASSERT(bits != 0);
28 #if defined(DAWN_COMPILER_MSVC)
29 unsigned long firstBitIndex = 0ul;
30 unsigned char ret = _BitScanForward(&firstBitIndex, bits);
31 ASSERT(ret != 0);
32 return firstBitIndex;
33 #else
34 return static_cast<uint32_t>(__builtin_ctz(bits));
35 #endif
36 }
37
Log2(uint32_t value)38 uint32_t Log2(uint32_t value) {
39 ASSERT(value != 0);
40 #if defined(DAWN_COMPILER_MSVC)
41 unsigned long firstBitIndex = 0ul;
42 unsigned char ret = _BitScanReverse(&firstBitIndex, value);
43 ASSERT(ret != 0);
44 return firstBitIndex;
45 #else
46 return 31 - static_cast<uint32_t>(__builtin_clz(value));
47 #endif
48 }
49
IsPowerOfTwo(size_t n)50 bool IsPowerOfTwo(size_t n) {
51 ASSERT(n != 0);
52 return (n & (n - 1)) == 0;
53 }
54
IsPtrAligned(const void * ptr,size_t alignment)55 bool IsPtrAligned(const void* ptr, size_t alignment) {
56 ASSERT(IsPowerOfTwo(alignment));
57 ASSERT(alignment != 0);
58 return (reinterpret_cast<size_t>(ptr) & (alignment - 1)) == 0;
59 }
60
AlignVoidPtr(void * ptr,size_t alignment)61 void* AlignVoidPtr(void* ptr, size_t alignment) {
62 ASSERT(IsPowerOfTwo(alignment));
63 ASSERT(alignment != 0);
64 return reinterpret_cast<void*>((reinterpret_cast<size_t>(ptr) + (alignment - 1)) &
65 ~(alignment - 1));
66 }
67
IsAligned(uint32_t value,size_t alignment)68 bool IsAligned(uint32_t value, size_t alignment) {
69 ASSERT(alignment <= UINT32_MAX);
70 ASSERT(IsPowerOfTwo(alignment));
71 ASSERT(alignment != 0);
72 uint32_t alignment32 = static_cast<uint32_t>(alignment);
73 return (value & (alignment32 - 1)) == 0;
74 }
75
Align(uint32_t value,size_t alignment)76 uint32_t Align(uint32_t value, size_t alignment) {
77 ASSERT(alignment <= UINT32_MAX);
78 ASSERT(IsPowerOfTwo(alignment));
79 ASSERT(alignment != 0);
80 uint32_t alignment32 = static_cast<uint32_t>(alignment);
81 return (value + (alignment32 - 1)) & ~(alignment32 - 1);
82 }
83
Float32ToFloat16(float fp32)84 uint16_t Float32ToFloat16(float fp32) {
85 uint32_t fp32i = BitCast<uint32_t>(fp32);
86 uint32_t sign16 = (fp32i & 0x80000000) >> 16;
87 uint32_t mantissaAndExponent = fp32i & 0x7FFFFFFF;
88
89 if (mantissaAndExponent > 0x7F800000) { // NaN
90 return 0x7FFF;
91 } else if (mantissaAndExponent > 0x47FFEFFF) { // Infinity
92 return static_cast<uint16_t>(sign16 | 0x7C00);
93 } else if (mantissaAndExponent < 0x38800000) { // Denormal
94 uint32_t mantissa = (mantissaAndExponent & 0x007FFFFF) | 0x00800000;
95 int32_t exponent = 113 - (mantissaAndExponent >> 23);
96
97 if (exponent < 24) {
98 mantissaAndExponent = mantissa >> exponent;
99 } else {
100 mantissaAndExponent = 0;
101 }
102
103 return static_cast<uint16_t>(
104 sign16 | (mantissaAndExponent + 0x00000FFF + ((mantissaAndExponent >> 13) & 1)) >> 13);
105 } else {
106 return static_cast<uint16_t>(sign16 | (mantissaAndExponent + 0xC8000000 + 0x00000FFF +
107 ((mantissaAndExponent >> 13) & 1)) >>
108 13);
109 }
110 }
111
IsFloat16NaN(uint16_t fp16)112 bool IsFloat16NaN(uint16_t fp16) {
113 return (fp16 & 0x7FFF) > 0x7C00;
114 }
115
116 // Based on the Khronos Data Format Specification 1.2 Section 13.3 sRGB transfer functions
SRGBToLinear(float srgb)117 float SRGBToLinear(float srgb) {
118 // sRGB is always used in unsigned normalized formats so clamp to [0.0, 1.0]
119 if (srgb <= 0.0f) {
120 return 0.0f;
121 } else if (srgb > 1.0f) {
122 return 1.0f;
123 }
124
125 if (srgb < 0.04045f) {
126 return srgb / 12.92f;
127 } else {
128 return std::pow((srgb + 0.055f) / 1.055f, 2.4f);
129 }
130 }
131