Backed out 3 changesets (bug 1790375) for causing wd failures on fetch_error.py....
[gecko.git] / third_party / jpeg-xl / lib / jpegli / memory_manager.cc
blob3a8f230e63800190e3dc28e3086082f07cc2d466
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file.
6 #include "lib/jpegli/memory_manager.h"
8 #include <string.h>
10 #include <hwy/aligned_allocator.h>
11 #include <vector>
13 #include "lib/jpegli/common_internal.h"
14 #include "lib/jpegli/error.h"
16 struct jvirt_sarray_control {
17 JSAMPARRAY full_buffer;
18 size_t numrows;
19 JDIMENSION maxaccess;
22 struct jvirt_barray_control {
23 JBLOCKARRAY full_buffer;
24 size_t numrows;
25 JDIMENSION maxaccess;
28 namespace jpegli {
30 namespace {
32 struct MemoryManager {
33 struct jpeg_memory_mgr pub;
34 std::vector<void*> owned_ptrs[2 * JPOOL_NUMPOOLS];
35 uint64_t pool_memory_usage[2 * JPOOL_NUMPOOLS];
36 uint64_t total_memory_usage;
37 uint64_t peak_memory_usage;
40 void* Alloc(j_common_ptr cinfo, int pool_id, size_t sizeofobject) {
41 MemoryManager* mem = reinterpret_cast<MemoryManager*>(cinfo->mem);
42 if (pool_id < 0 || pool_id >= 2 * JPOOL_NUMPOOLS) {
43 JPEGLI_ERROR("Invalid pool id %d", pool_id);
45 if (mem->pub.max_memory_to_use > 0 &&
46 mem->total_memory_usage + static_cast<uint64_t>(sizeofobject) >
47 static_cast<uint64_t>(mem->pub.max_memory_to_use)) {
48 JPEGLI_ERROR("Total memory usage exceeding %ld",
49 mem->pub.max_memory_to_use);
51 void* p;
52 if (pool_id < JPOOL_NUMPOOLS) {
53 p = malloc(sizeofobject);
54 } else {
55 p = hwy::AllocateAlignedBytes(sizeofobject, nullptr, nullptr);
57 if (p == nullptr) {
58 JPEGLI_ERROR("Out of memory");
60 mem->owned_ptrs[pool_id].push_back(p);
61 mem->pool_memory_usage[pool_id] += sizeofobject;
62 mem->total_memory_usage += sizeofobject;
63 mem->peak_memory_usage =
64 std::max(mem->peak_memory_usage, mem->total_memory_usage);
65 return p;
68 constexpr size_t gcd(size_t a, size_t b) { return b == 0 ? a : gcd(b, a % b); }
69 constexpr size_t lcm(size_t a, size_t b) { return (a * b) / gcd(a, b); }
71 template <typename T>
72 T** Alloc2dArray(j_common_ptr cinfo, int pool_id, JDIMENSION samplesperrow,
73 JDIMENSION numrows) {
74 T** array = Allocate<T*>(cinfo, numrows, pool_id);
75 // Always use aligned allocator for large 2d arrays.
76 if (pool_id < JPOOL_NUMPOOLS) {
77 pool_id += JPOOL_NUMPOOLS;
79 size_t alignment = lcm(sizeof(T), HWY_ALIGNMENT);
80 size_t memstride = RoundUpTo(samplesperrow * sizeof(T), alignment);
81 size_t stride = memstride / sizeof(T);
82 T* buffer = Allocate<T>(cinfo, numrows * stride, pool_id);
83 for (size_t i = 0; i < numrows; ++i) {
84 array[i] = &buffer[i * stride];
86 return array;
89 template <typename Control, typename T>
90 Control* RequestVirtualArray(j_common_ptr cinfo, int pool_id, boolean pre_zero,
91 JDIMENSION samplesperrow, JDIMENSION numrows,
92 JDIMENSION maxaccess) {
93 if (pool_id != JPOOL_IMAGE) {
94 JPEGLI_ERROR("Only image lifetime virtual arrays are supported.");
96 Control* p = Allocate<Control>(cinfo, 1, pool_id);
97 p->full_buffer = Alloc2dArray<T>(cinfo, pool_id, samplesperrow, numrows);
98 p->numrows = numrows;
99 p->maxaccess = maxaccess;
100 if (pre_zero) {
101 for (size_t i = 0; i < numrows; ++i) {
102 memset(p->full_buffer[i], 0, samplesperrow * sizeof(T));
105 return p;
108 void RealizeVirtualArrays(j_common_ptr cinfo) {
109 // Nothing to do, the full arrays were realized at request time already.
112 template <typename Control, typename T>
113 T** AccessVirtualArray(j_common_ptr cinfo, Control* ptr, JDIMENSION start_row,
114 JDIMENSION num_rows, boolean writable) {
115 if (num_rows > ptr->maxaccess) {
116 JPEGLI_ERROR("Invalid virtual array access, num rows %u vs max rows %u",
117 num_rows, ptr->maxaccess);
119 if (start_row + num_rows > ptr->numrows) {
120 JPEGLI_ERROR("Invalid virtual array access, %u vs %u total rows",
121 start_row + num_rows, ptr->numrows);
123 if (ptr->full_buffer == nullptr) {
124 JPEGLI_ERROR("Invalid virtual array access, array not realized.");
126 return ptr->full_buffer + start_row;
129 void ClearPool(j_common_ptr cinfo, int pool_id) {
130 MemoryManager* mem = reinterpret_cast<MemoryManager*>(cinfo->mem);
131 mem->owned_ptrs[pool_id].clear();
132 mem->total_memory_usage -= mem->pool_memory_usage[pool_id];
133 mem->pool_memory_usage[pool_id] = 0;
136 void FreePool(j_common_ptr cinfo, int pool_id) {
137 MemoryManager* mem = reinterpret_cast<MemoryManager*>(cinfo->mem);
138 if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) {
139 JPEGLI_ERROR("Invalid pool id %d", pool_id);
141 for (void* ptr : mem->owned_ptrs[pool_id]) {
142 free(ptr);
144 ClearPool(cinfo, pool_id);
145 for (void* ptr : mem->owned_ptrs[JPOOL_NUMPOOLS + pool_id]) {
146 hwy::FreeAlignedBytes(ptr, nullptr, nullptr);
148 ClearPool(cinfo, JPOOL_NUMPOOLS + pool_id);
151 void SelfDestruct(j_common_ptr cinfo) {
152 MemoryManager* mem = reinterpret_cast<MemoryManager*>(cinfo->mem);
153 for (int pool_id = 0; pool_id < JPOOL_NUMPOOLS; ++pool_id) {
154 FreePool(cinfo, pool_id);
156 delete mem;
157 cinfo->mem = nullptr;
160 } // namespace
162 void InitMemoryManager(j_common_ptr cinfo) {
163 MemoryManager* mem = new MemoryManager;
164 mem->pub.alloc_small = jpegli::Alloc;
165 mem->pub.alloc_large = jpegli::Alloc;
166 mem->pub.alloc_sarray = jpegli::Alloc2dArray<JSAMPLE>;
167 mem->pub.alloc_barray = jpegli::Alloc2dArray<JBLOCK>;
168 mem->pub.request_virt_sarray =
169 jpegli::RequestVirtualArray<jvirt_sarray_control, JSAMPLE>;
170 mem->pub.request_virt_barray =
171 jpegli::RequestVirtualArray<jvirt_barray_control, JBLOCK>;
172 mem->pub.realize_virt_arrays = jpegli::RealizeVirtualArrays;
173 mem->pub.access_virt_sarray =
174 jpegli::AccessVirtualArray<jvirt_sarray_control, JSAMPLE>;
175 mem->pub.access_virt_barray =
176 jpegli::AccessVirtualArray<jvirt_barray_control, JBLOCK>;
177 mem->pub.free_pool = jpegli::FreePool;
178 mem->pub.self_destruct = jpegli::SelfDestruct;
179 mem->pub.max_memory_to_use = 0;
180 mem->total_memory_usage = 0;
181 mem->peak_memory_usage = 0;
182 memset(mem->pool_memory_usage, 0, sizeof(mem->pool_memory_usage));
183 cinfo->mem = reinterpret_cast<struct jpeg_memory_mgr*>(mem);
186 } // namespace jpegli