1 /*
2 * Copyright 2025 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18
19 #include "allocator.h"
20
21 #include <stdlib.h>
22
23 #include <algorithm>
24
25 #include <log/log.h>
26
27 // #define ENABLE_ALLOC_CALLSTACKS 1
28 #if ENABLE_ALLOC_CALLSTACKS
29 #include <utils/CallStack.h>
30 #define ALOGD_CALLSTACK(...) \
31 do { \
32 ALOGD(__VA_ARGS__); \
33 android::CallStack callstack; \
34 callstack.update(); \
35 callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, " "); \
36 } while (false)
37 #else
38 #define ALOGD_CALLSTACK(...) \
39 do { \
40 } while (false)
41 #endif
42
43 namespace vulkan {
44 namespace driver {
45
46 namespace {
47
DefaultAllocate(void *,size_t size,size_t alignment,VkSystemAllocationScope)48 VKAPI_ATTR void* DefaultAllocate(void*,
49 size_t size,
50 size_t alignment,
51 VkSystemAllocationScope) {
52 void* ptr = nullptr;
53 // Vulkan requires 'alignment' to be a power of two, but posix_memalign
54 // additionally requires that it be at least sizeof(void*).
55 int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size);
56 ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment,
57 ret, ptr);
58 return ret == 0 ? ptr : nullptr;
59 }
60
61 // This function is marked `noinline` so that LLVM can't infer an object size
62 // for FORTIFY through it, given that it's abusing malloc_usable_size().
63 __attribute__((__noinline__))
DefaultReallocate(void *,void * ptr,size_t size,size_t alignment,VkSystemAllocationScope)64 VKAPI_ATTR void* DefaultReallocate(void*,
65 void* ptr,
66 size_t size,
67 size_t alignment,
68 VkSystemAllocationScope) {
69 if (size == 0) {
70 free(ptr);
71 return nullptr;
72 }
73
74 // TODO(b/143295633): Right now we never shrink allocations; if the new
75 // request is smaller than the existing chunk, we just continue using it.
76 // Right now the loader never reallocs, so this doesn't matter. If that
77 // changes, or if this code is copied into some other project, this should
78 // probably have a heuristic to allocate-copy-free when doing so will save
79 // "enough" space.
80 size_t old_size = ptr ? malloc_usable_size(ptr) : 0;
81 if (size <= old_size)
82 return ptr;
83
84 void* new_ptr = nullptr;
85 if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0)
86 return nullptr;
87 if (ptr) {
88 memcpy(new_ptr, ptr, std::min(old_size, size));
89 free(ptr);
90 }
91 return new_ptr;
92 }
93
DefaultFree(void *,void * ptr)94 VKAPI_ATTR void DefaultFree(void*, void* ptr) {
95 ALOGD_CALLSTACK("Free: %p", ptr);
96 free(ptr);
97 }
98
99 } // anonymous namespace
100
GetDefaultAllocator()101 const VkAllocationCallbacks& GetDefaultAllocator() {
102 static const VkAllocationCallbacks kDefaultAllocCallbacks = {
103 .pUserData = nullptr,
104 .pfnAllocation = DefaultAllocate,
105 .pfnReallocation = DefaultReallocate,
106 .pfnFree = DefaultFree,
107 };
108
109 return kDefaultAllocCallbacks;
110 }
111
112 } // namespace driver
113 } // namespace vulkan
114