summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/jpegli/memory_manager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/jpeg-xl/lib/jpegli/memory_manager.cc')
-rw-r--r--third_party/jpeg-xl/lib/jpegli/memory_manager.cc181
1 files changed, 181 insertions, 0 deletions
diff --git a/third_party/jpeg-xl/lib/jpegli/memory_manager.cc b/third_party/jpeg-xl/lib/jpegli/memory_manager.cc
new file mode 100644
index 0000000000..f6530d8f02
--- /dev/null
+++ b/third_party/jpeg-xl/lib/jpegli/memory_manager.cc
@@ -0,0 +1,181 @@
+// Copyright (c) the JPEG XL Project 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 "lib/jpegli/memory_manager.h"
+
+#include <string.h>
+
+#include <hwy/aligned_allocator.h>
+#include <vector>
+
+#include "lib/jpegli/common_internal.h"
+#include "lib/jpegli/error.h"
+
+struct jvirt_sarray_control {
+ JSAMPARRAY full_buffer;
+ size_t numrows;
+ JDIMENSION maxaccess;
+};
+
+struct jvirt_barray_control {
+ JBLOCKARRAY full_buffer;
+ size_t numrows;
+ JDIMENSION maxaccess;
+};
+
+namespace jpegli {
+
+namespace {
+
+struct MemoryManager {
+ struct jpeg_memory_mgr pub;
+ std::vector<void*> owned_ptrs[2 * JPOOL_NUMPOOLS];
+ uint64_t pool_memory_usage[2 * JPOOL_NUMPOOLS];
+ uint64_t total_memory_usage;
+ uint64_t peak_memory_usage;
+};
+
+void* Alloc(j_common_ptr cinfo, int pool_id, size_t sizeofobject) {
+ MemoryManager* mem = reinterpret_cast<MemoryManager*>(cinfo->mem);
+ if (pool_id < 0 || pool_id >= 2 * JPOOL_NUMPOOLS) {
+ JPEGLI_ERROR("Invalid pool id %d", pool_id);
+ }
+ if (mem->pub.max_memory_to_use > 0 &&
+ mem->total_memory_usage + static_cast<uint64_t>(sizeofobject) >
+ static_cast<uint64_t>(mem->pub.max_memory_to_use)) {
+ JPEGLI_ERROR("Total memory usage exceeding %ld",
+ mem->pub.max_memory_to_use);
+ }
+ void* p;
+ if (pool_id < JPOOL_NUMPOOLS) {
+ p = malloc(sizeofobject);
+ } else {
+ p = hwy::AllocateAlignedBytes(sizeofobject, nullptr, nullptr);
+ }
+ if (p == nullptr) {
+ JPEGLI_ERROR("Out of memory");
+ }
+ mem->owned_ptrs[pool_id].push_back(p);
+ mem->pool_memory_usage[pool_id] += sizeofobject;
+ mem->total_memory_usage += sizeofobject;
+ mem->peak_memory_usage =
+ std::max(mem->peak_memory_usage, mem->total_memory_usage);
+ return p;
+}
+
+template <typename T>
+T** Alloc2dArray(j_common_ptr cinfo, int pool_id, JDIMENSION samplesperrow,
+ JDIMENSION numrows) {
+ T** array = Allocate<T*>(cinfo, numrows, pool_id);
+ // Always use aligned allocator for large 2d arrays.
+ if (pool_id < JPOOL_NUMPOOLS) {
+ pool_id += JPOOL_NUMPOOLS;
+ }
+ size_t stride = RoundUpTo(samplesperrow, HWY_ALIGNMENT);
+ T* buffer = Allocate<T>(cinfo, numrows * stride, pool_id);
+ for (size_t i = 0; i < numrows; ++i) {
+ array[i] = &buffer[i * stride];
+ }
+ return array;
+}
+
+template <typename Control, typename T>
+Control* RequestVirtualArray(j_common_ptr cinfo, int pool_id, boolean pre_zero,
+ JDIMENSION samplesperrow, JDIMENSION numrows,
+ JDIMENSION maxaccess) {
+ if (pool_id != JPOOL_IMAGE) {
+ JPEGLI_ERROR("Only image lifetime virtual arrays are supported.");
+ }
+ Control* p = Allocate<Control>(cinfo, 1, pool_id);
+ p->full_buffer = Alloc2dArray<T>(cinfo, pool_id, samplesperrow, numrows);
+ p->numrows = numrows;
+ p->maxaccess = maxaccess;
+ if (pre_zero) {
+ for (size_t i = 0; i < numrows; ++i) {
+ memset(p->full_buffer[i], 0, samplesperrow * sizeof(T));
+ }
+ }
+ return p;
+}
+
+void RealizeVirtualArrays(j_common_ptr cinfo) {
+ // Nothing to do, the full arrays were realized at request time already.
+}
+
+template <typename Control, typename T>
+T** AccessVirtualArray(j_common_ptr cinfo, Control* ptr, JDIMENSION start_row,
+ JDIMENSION num_rows, boolean writable) {
+ if (num_rows > ptr->maxaccess) {
+ JPEGLI_ERROR("Invalid virtual array access, num rows %u vs max rows %u",
+ num_rows, ptr->maxaccess);
+ }
+ if (start_row + num_rows > ptr->numrows) {
+ JPEGLI_ERROR("Invalid virtual array access, %u vs %u total rows",
+ start_row + num_rows, ptr->numrows);
+ }
+ if (ptr->full_buffer == nullptr) {
+ JPEGLI_ERROR("Invalid virtual array access, array not realized.");
+ }
+ return ptr->full_buffer + start_row;
+}
+
+void ClearPool(j_common_ptr cinfo, int pool_id) {
+ MemoryManager* mem = reinterpret_cast<MemoryManager*>(cinfo->mem);
+ mem->owned_ptrs[pool_id].clear();
+ mem->total_memory_usage -= mem->pool_memory_usage[pool_id];
+ mem->pool_memory_usage[pool_id] = 0;
+}
+
+void FreePool(j_common_ptr cinfo, int pool_id) {
+ MemoryManager* mem = reinterpret_cast<MemoryManager*>(cinfo->mem);
+ if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) {
+ JPEGLI_ERROR("Invalid pool id %d", pool_id);
+ }
+ for (void* ptr : mem->owned_ptrs[pool_id]) {
+ free(ptr);
+ }
+ ClearPool(cinfo, pool_id);
+ for (void* ptr : mem->owned_ptrs[JPOOL_NUMPOOLS + pool_id]) {
+ hwy::FreeAlignedBytes(ptr, nullptr, nullptr);
+ }
+ ClearPool(cinfo, JPOOL_NUMPOOLS + pool_id);
+}
+
+void SelfDestruct(j_common_ptr cinfo) {
+ MemoryManager* mem = reinterpret_cast<MemoryManager*>(cinfo->mem);
+ for (int pool_id = 0; pool_id < JPOOL_NUMPOOLS; ++pool_id) {
+ FreePool(cinfo, pool_id);
+ }
+ delete mem;
+ cinfo->mem = nullptr;
+}
+
+} // namespace
+
+void InitMemoryManager(j_common_ptr cinfo) {
+ MemoryManager* mem = new MemoryManager;
+ mem->pub.alloc_small = jpegli::Alloc;
+ mem->pub.alloc_large = jpegli::Alloc;
+ mem->pub.alloc_sarray = jpegli::Alloc2dArray<JSAMPLE>;
+ mem->pub.alloc_barray = jpegli::Alloc2dArray<JBLOCK>;
+ mem->pub.request_virt_sarray =
+ jpegli::RequestVirtualArray<jvirt_sarray_control, JSAMPLE>;
+ mem->pub.request_virt_barray =
+ jpegli::RequestVirtualArray<jvirt_barray_control, JBLOCK>;
+ mem->pub.realize_virt_arrays = jpegli::RealizeVirtualArrays;
+ mem->pub.access_virt_sarray =
+ jpegli::AccessVirtualArray<jvirt_sarray_control, JSAMPLE>;
+ mem->pub.access_virt_barray =
+ jpegli::AccessVirtualArray<jvirt_barray_control, JBLOCK>;
+ mem->pub.free_pool = jpegli::FreePool;
+ mem->pub.self_destruct = jpegli::SelfDestruct;
+ mem->pub.max_memory_to_use = 0;
+ mem->total_memory_usage = 0;
+ mem->peak_memory_usage = 0;
+ memset(mem->pool_memory_usage, 0, sizeof(mem->pool_memory_usage));
+ cinfo->mem = reinterpret_cast<struct jpeg_memory_mgr*>(mem);
+}
+
+} // namespace jpegli