Branch data Line data Source code
1 : : /*
2 : : * This file is part of libplacebo.
3 : : *
4 : : * libplacebo is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Lesser General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2.1 of the License, or (at your option) any later version.
8 : : *
9 : : * libplacebo is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : : * GNU Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General Public
15 : : * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
16 : : */
17 : :
18 : : #pragma once
19 : :
20 : : #define __STDC_FORMAT_MACROS
21 : :
22 : : #ifdef __cplusplus
23 : : #include <version>
24 : : #endif
25 : :
26 : : #if !defined(__cplusplus) || defined(__cpp_lib_stdatomic_h)
27 : : #define PL_HAVE_STDATOMIC
28 : : #endif
29 : :
30 : : #ifdef PL_HAVE_STDATOMIC
31 : : #include <stdatomic.h>
32 : : #endif
33 : : #include <stdbool.h>
34 : : #include <stddef.h>
35 : : #include <stdint.h>
36 : : #include <stdlib.h>
37 : : #include <inttypes.h>
38 : :
39 : : #if defined(__MINGW32__) && !defined(__clang__)
40 : : #define PL_PRINTF(fmt, va) __attribute__ ((format(gnu_printf, fmt, va))) \
41 : : __attribute__ ((nonnull(fmt)))
42 : : #elif defined(__GNUC__)
43 : : #define PL_PRINTF(fmt, va) __attribute__ ((format(printf, fmt, va))) \
44 : : __attribute__ ((nonnull(fmt)))
45 : : #else
46 : : #define PL_PRINTF(fmt, va)
47 : : #endif
48 : :
49 : : #define PL_NOINLINE __attribute__((noinline))
50 : :
51 : : #include "os.h"
52 : :
53 : : #include "config_internal.h"
54 : :
55 : : #define PL_DEPRECATED_IN(VER)
56 : :
57 : : #include <libplacebo/config.h>
58 : :
59 : : #include "pl_assert.h"
60 : : #include "pl_alloc.h"
61 : : #include "pl_clock.h"
62 : : #include "pl_string.h"
63 : :
64 : : #if PL_API_VER != BUILD_API_VER
65 : : #error Header mismatch? <libplacebo/config.h> pulled from elsewhere!
66 : : #endif
67 : :
68 : : // Divide a number while rounding up (careful: double-eval)
69 : : #define PL_DIV_UP(x, y) (((x) + (y) - 1) / (y))
70 : :
71 : : // Align up to the nearest multiple of an arbitrary alignment, which may also
72 : : // be 0 to signal no alignment requirements.
73 : : #define PL_ALIGN(x, align) ((align) ? PL_DIV_UP(x, align) * (align) : (x))
74 : :
75 : : // This is faster but must only be called on positive powers of two.
76 : : #define PL_ALIGN2(x, align) (((x) + (align) - 1) & ~((align) - 1))
77 : :
78 : : // Returns the log base 2 of an unsigned long long
79 : : #define PL_LOG2(x) ((unsigned) (8*sizeof (unsigned long long) - __builtin_clzll((x)) - 1))
80 : :
81 : : // Rounds a number up to the nearest power of two
82 : : #define PL_ALIGN_POT(x) (0x1LLU << (PL_LOG2((x) - 1) + 1))
83 : :
84 : : // Right shift a number while rounding up
85 : : #define PL_RSHIFT_UP(x, s) -((-(x)) >> (s))
86 : :
87 : : // Returns whether or not a number is a power of two (or zero)
88 : : #define PL_ISPOT(x) (((x) & ((x) - 1)) == 0)
89 : :
90 : : // Returns the size of a static array with known size.
91 : : #define PL_ARRAY_SIZE(s) (sizeof(s) / sizeof((s)[0]))
92 : :
93 : : // Swaps two variables
94 : : #define PL_SWAP(a, b) \
95 : : do { \
96 : : __typeof__ (a) _tmp = (a); \
97 : : (a) = (b); \
98 : : (b) = _tmp; \
99 : : } while (0)
100 : :
101 : : // Helper functions for transposing a matrix in-place.
102 : : #define PL_TRANSPOSE_DIM(d, m) \
103 : : pl_transpose((d), (float[(d)*(d)]){0}, (const float *)(m))
104 : :
105 : : #define PL_TRANSPOSE_2X2(m) PL_TRANSPOSE_DIM(2, m)
106 : : #define PL_TRANSPOSE_3X3(m) PL_TRANSPOSE_DIM(3, m)
107 : : #define PL_TRANSPOSE_4X4(m) PL_TRANSPOSE_DIM(4, m)
108 : :
109 : : static inline float *pl_transpose(int dim, float *out, const float *in)
110 : : {
111 [ + + + + : 6016 : for (int i = 0; i < dim; i++) {
+ + + + ]
112 [ + + + + : 16128 : for (int j = 0; j < dim; j++)
+ + + + ]
113 : 11776 : out[i * dim + j] = in[j * dim + i];
114 : : }
115 : :
116 : : return out;
117 : : }
118 : :
119 : : // Helper functions for some common numeric operations (careful: double-eval)
120 : : #define PL_MAX(x, y) ((x) > (y) ? (x) : (y))
121 : : #define PL_MAX3(x, y, z) PL_MAX(PL_MAX(x, y), z)
122 : : #define PL_MIN(x, y) ((x) < (y) ? (x) : (y))
123 : : #define PL_CLAMP(x, l, h) ((x) < (l) ? (l) : (x) > (h) ? (h) : (x))
124 : : #define PL_CMP(a, b) (((a) > (b)) - ((a) < (b)))
125 : : #define PL_DEF(x, d) ((x) ? (x) : (d))
126 : : #define PL_SQUARE(x) ((x) * (x))
127 : : #define PL_CUBE(x) ((x) * (x) * (x))
128 : : #define PL_MIX(a, b, x) ((x) * (b) + (1 - (x)) * (a))
129 : :
130 : : static inline float pl_smoothstep(float edge0, float edge1, float x)
131 : : {
132 [ - + - + ]: 6566133 : if (edge0 == edge1)
133 [ # # # # ]: 0 : return x >= edge0;
134 : 6566133 : x = (x - edge0) / (edge1 - edge0);
135 [ + + + + : 6566133 : x = PL_CLAMP(x, 0.0f, 1.0f);
+ + + + ]
136 : 6566133 : return x * x * (3.0f - 2.0f * x);
137 : : }
138 : :
139 : : // Helpers for doing alignment calculations
140 : 5391 : static inline size_t pl_gcd(size_t x, size_t y)
141 : : {
142 [ + - ]: 5391 : assert(x && y);
143 [ + + ]: 14119 : while (y) {
144 : : size_t tmp = y;
145 : 8728 : y = x % y;
146 : : x = tmp;
147 : : }
148 : :
149 : 5391 : return x;
150 : : }
151 : :
152 : 5391 : static inline size_t pl_lcm(size_t x, size_t y)
153 : : {
154 [ - + ]: 5391 : assert(x && y);
155 : 5391 : return x * (y / pl_gcd(x, y));
156 : : }
157 : :
158 : : // Conditional abort() macro that depends on the configuration option
159 : : #ifdef PL_DEBUG_ABORT
160 : : # define pl_debug_abort() do { \
161 : : fprintf(stderr, "pl_debug_abort() triggered!\n"); \
162 : : abort(); \
163 : : } while (0)
164 : : #else
165 : : # define pl_debug_abort() do {} while (0)
166 : : #endif
167 : :
168 : : #ifdef PL_HAVE_STDATOMIC
169 : :
170 : : // Refcounting helpers
171 : : typedef atomic_uint_fast32_t pl_rc_t;
172 : : #define pl_rc_init(rc) atomic_init(rc, 1)
173 : : #define pl_rc_ref(rc) ((void) atomic_fetch_add_explicit(rc, 1, memory_order_acquire))
174 : : #define pl_rc_deref(rc) (atomic_fetch_sub_explicit(rc, 1, memory_order_release) == 1)
175 : : #define pl_rc_count(rc) atomic_load(rc)
176 : :
177 : : #endif
178 : :
179 : : #define pl_unreachable() (assert(!"unreachable"), __builtin_unreachable())
180 : :
181 : : // Helper for parameter validation
182 : : #define pl_require(ctx, expr) \
183 : : do { \
184 : : if (!(expr)) { \
185 : : PL_ERR(ctx, "Validation failed: %s (%s:%d)", \
186 : : #expr, __FILE__, __LINE__); \
187 : : pl_log_stack_trace(ctx->log, PL_LOG_ERR); \
188 : : pl_debug_abort(); \
189 : : goto error; \
190 : : } \
191 : : } while (0)
|