Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
mem_alloc.h
Go to the documentation of this file.
1/*
2 This file is part of Ansel,
3 Copyright (C) 2026 Aurélien PIERRE.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18#ifndef DT_SYSTEM_MEM_ALLOC_H
19#define DT_SYSTEM_MEM_ALLOC_H
20
21/* Cacheline-aligned memory: alignment constants/attributes and the dt_alloc/dt_free
22 * family. Self-contained on purpose: low-level compute units include this instead of
23 * darktable.h. The pixelpipe-cache-tracked allocators
24 * (dt_pixelpipe_cache_alloc_*) are NOT here — they reference the darktable global and
25 * stay with the orchestrator. */
26
27#include "system/macros.h"
28
29#include <glib.h>
30#include <stdint.h>
31#include <stdlib.h>
32#include <string.h>
33
34#ifdef _WIN32
35#include <malloc.h> // _aligned_malloc / _aligned_free
36#endif
37
38#ifdef __cplusplus
39extern "C" {
40#endif
41
51#define DT_IS_ALIGNED(x) __builtin_assume_aligned(x, DT_CACHELINE_BYTES)
52
53/* Size of a CPU cacheline, in bytes, floats and 4-float pixels.
54 *
55 * These are COMPILE-TIME constants chosen per target, not the running machine's real
56 * cacheline: a binary built for x86-64 and run under emulation on Apple Silicon keeps 64.
57 * They set the alignment of every dt_alloc_align() buffer and of DT_ALIGNED_ARRAY, so a
58 * value smaller than the hardware's costs performance, and one larger costs memory --
59 * neither is a correctness problem, which is why the mismatch is easy to miss.
60 */
61#if defined(__APPLE__) && defined(__aarch64__)
62 #define DT_CACHELINE_BYTES 128
63 #define DT_CACHELINE_FLOATS 32
64 #define DT_CACHELINE_PIXELS 8
65#else
66 #define DT_CACHELINE_BYTES 64
67 #define DT_CACHELINE_FLOATS 16
68 #define DT_CACHELINE_PIXELS 4
69#endif /* __APPLE__ && __aarch64__ */
70
80#define DT_ALIGNED_ARRAY __attribute__((aligned(DT_CACHELINE_BYTES)))
81
85#define DT_ALIGNED_PIXEL __attribute__((aligned(16)))
86
88static inline gboolean dt_is_aligned(const void *pointer, size_t byte_count)
89{
90 return (uintptr_t)pointer % byte_count == 0;
91}
92
99static inline size_t dt_round_size(const size_t size, const size_t alignment)
100{
101 // Round the size of a buffer to the closest higher multiple
102 return ((size % alignment) == 0) ? size : ((size - 1) / alignment + 1) * alignment;
103}
104
111static inline size_t dt_round_size_sse(const size_t size)
112{
113 // Round the size of a buffer to the closest 64 higher multiple
114 return dt_round_size(size, 64);
115}
116
122static inline void *dt_alloc_align_internal(size_t size)
123{
124 const size_t alignment = DT_CACHELINE_BYTES;
125 const size_t aligned_size = dt_round_size(size, alignment);
126#if defined(__FreeBSD_version) && __FreeBSD_version < 700013
127 return malloc(aligned_size);
128#elif defined(_WIN32)
129 return _aligned_malloc(aligned_size, alignment);
130#else
131 void *ptr = NULL;
132 if(posix_memalign(&ptr, alignment, aligned_size)) return NULL;
133 return ptr;
134#endif
135}
136
155void *dt_alloc_align(size_t size);
156
171#define dt_free(ptr) \
172 if(!IS_NULL_PTR(ptr)) \
173 { \
174 g_free((void *)(ptr)); \
175 *(void **)(&(ptr)) = NULL; \
176 }
177
184static inline void dt_free_gpointer(gpointer ptr)
185{
186 g_free(ptr);
187 ptr = NULL;
188}
189
192#ifdef _WIN32
193 static inline void dt_free_align_ptr(void *mem)
194 {
195 _aligned_free(mem);
196 }
197#else
198 static inline void dt_free_align_ptr(void *mem)
199 {
200 dt_free(mem);
201 }
202#endif
203
214#define dt_free_align(ptr) \
215 if(!IS_NULL_PTR(ptr)) \
216 { \
217 dt_free_align_ptr((void *)(ptr)); \
218 *(void **)(&(ptr)) = NULL; \
219 }
220
225static inline void* dt_calloc_align(size_t size)
226{
227 void *buf = dt_alloc_align(size);
228 if(buf) memset(buf, 0, size);
229 return buf;
230}
235static inline float *dt_alloc_align_float(size_t pixels)
236{
237 return (float*)__builtin_assume_aligned(dt_alloc_align(pixels * sizeof(float)), DT_CACHELINE_BYTES);
238}
241static inline float *dt_calloc_align_float(size_t pixels)
242{
243 float *const buf = (float*)dt_alloc_align(pixels * sizeof(float));
244 if(buf) memset(buf, 0, pixels * sizeof(float));
245 return (float*)__builtin_assume_aligned(buf, DT_CACHELINE_BYTES);
246}
251static inline void * dt_check_sse_aligned(void * pointer)
252{
254 return __builtin_assume_aligned(pointer, DT_CACHELINE_BYTES);
255 else
256 return NULL;
257}
258
270static inline void memset_zero(void *const buffer, size_t size)
271{
272 // Same as memset_s in C11. memset might be optimized away by compilers, this will not.
273 // Not parallelized or vectorized since it's applied only on "small" tiles.
274 for(size_t k = 0; k < size / sizeof(unsigned char); k++) {
275 unsigned char *const item = (unsigned char *const)buffer + k;
276 *item = 0;
277 }
278}
279
280#ifdef __cplusplus
281}
282#endif
283
284#endif // DT_SYSTEM_MEM_ALLOC_H
285
286// clang-format off
287// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
288// vim: shiftwidth=2 expandtab tabstop=2 cindent
289// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
290// clang-format on
float *const restrict const size_t k
static void memset_zero(void *const buffer, size_t size)
Set the memory buffer to zero as a pack of unsigned char.
Definition mem_alloc.h:270
static float * dt_calloc_align_float(size_t pixels)
dt_alloc_align_float() followed by a zero fill.
Definition mem_alloc.h:241
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
Definition mem_alloc.h:225
static void dt_free_align_ptr(void *mem)
Platform back-end for dt_free_align(). Call dt_free_align() instead: this one takes the pointer by va...
Definition mem_alloc.h:193
static float * dt_alloc_align_float(size_t pixels)
Allocate pixels floats, cacheline-aligned and marked as such.
Definition mem_alloc.h:235
static size_t dt_round_size_sse(const size_t size)
Round size up to the next multiple of 64.
Definition mem_alloc.h:111
static void * dt_check_sse_aligned(void *pointer)
Runtime-checked counterpart to DT_IS_ALIGNED().
Definition mem_alloc.h:251
static void * dt_alloc_align_internal(size_t size)
Platform back-end for dt_alloc_align(). Call dt_alloc_align() instead.
Definition mem_alloc.h:122
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
Definition mem_alloc.h:184
void * dt_alloc_align(size_t size)
Allocate cacheline-aligned memory.
Definition darktable.c:507
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
static size_t dt_round_size(const size_t size, const size_t alignment)
Round size UP to the next multiple of alignment.
Definition mem_alloc.h:99
static gboolean dt_is_aligned(const void *pointer, size_t byte_count)
Is pointer aligned on a byte_count boundary? Pure test, no side effect.
Definition mem_alloc.h:88
#define DT_CACHELINE_BYTES
Definition mem_alloc.h:66
size_t size
Definition mipmap_cache.c:3