1/*
2 * Copyright (c) 2019-2021 The Khronos Group Inc.
3 * Copyright (c) 2019-2021 Valve Corporation
4 * Copyright (c) 2019-2021 LunarG, Inc.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Author: Jon Ashburn <jon@lunarg.com>
19 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
20 * Author: Chia-I Wu <olvaffe@gmail.com>
21 * Author: Chia-I Wu <olv@lunarg.com>
22 * Author: Mark Lobodzinski <mark@LunarG.com>
23 * Author: Lenny Komow <lenny@lunarg.com>
24 * Author: Charles Giessen <charles@lunarg.com>
25 */
26
27#include "allocation.h"
28
29#include <stdlib.h>
30
31// A debug option to disable allocators at compile time to investigate future issues.
32#define DEBUG_DISABLE_APP_ALLOCATORS 0
33
34void *loader_alloc(const VkAllocationCallbacks *pAllocator, size_t size, VkSystemAllocationScope allocation_scope) {
35    void *pMemory = NULL;
36#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
37    {
38#else
39    if (pAllocator && pAllocator->pfnAllocation) {
40        // These are internal structures, so it's best to align everything to
41        // the largest unit size which is the size of a uint64_t.
42        pMemory = pAllocator->pfnAllocation(pAllocator->pUserData, size, sizeof(uint64_t), allocation_scope);
43    } else {
44#endif
45        pMemory = malloc(size);
46    }
47
48    return pMemory;
49}
50
51void *loader_calloc(const VkAllocationCallbacks *pAllocator, size_t size, VkSystemAllocationScope allocation_scope) {
52    void *pMemory = NULL;
53#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
54    {
55#else
56    if (pAllocator && pAllocator->pfnAllocation) {
57        // These are internal structures, so it's best to align everything to
58        // the largest unit size which is the size of a uint64_t.
59        pMemory = pAllocator->pfnAllocation(pAllocator->pUserData, size, sizeof(uint64_t), allocation_scope);
60        if (pMemory) {
61            memset(pMemory, 0, size);
62        }
63    } else {
64#endif
65        pMemory = calloc(1, size);
66    }
67
68    return pMemory;
69}
70
71void loader_free(const VkAllocationCallbacks *pAllocator, void *pMemory) {
72    if (pMemory != NULL) {
73#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
74        {
75#else
76        if (pAllocator && pAllocator->pfnFree) {
77            pAllocator->pfnFree(pAllocator->pUserData, pMemory);
78        } else {
79#endif
80            free(pMemory);
81        }
82    }
83}
84
85void *loader_realloc(const VkAllocationCallbacks *pAllocator, void *pMemory, size_t orig_size, size_t size,
86                     VkSystemAllocationScope allocation_scope) {
87    void *pNewMem = NULL;
88    if (pMemory == NULL || orig_size == 0) {
89        pNewMem = loader_alloc(pAllocator, size, allocation_scope);
90    } else if (size == 0) {
91        loader_free(pAllocator, pMemory);
92#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
93#else
94    } else if (pAllocator && pAllocator->pfnReallocation) {
95        // These are internal structures, so it's best to align everything to
96        // the largest unit size which is the size of a uint64_t.
97        pNewMem = pAllocator->pfnReallocation(pAllocator->pUserData, pMemory, size, sizeof(uint64_t), allocation_scope);
98#endif
99    } else {
100        pNewMem = realloc(pMemory, size);
101    }
102    return pNewMem;
103}
104
105void *loader_instance_heap_alloc(const struct loader_instance *inst, size_t size, VkSystemAllocationScope allocation_scope) {
106    return loader_alloc(inst ? &inst->alloc_callbacks : NULL, size, allocation_scope);
107}
108
109void *loader_instance_heap_calloc(const struct loader_instance *inst, size_t size, VkSystemAllocationScope allocation_scope) {
110    return loader_calloc(inst ? &inst->alloc_callbacks : NULL, size, allocation_scope);
111}
112
113void loader_instance_heap_free(const struct loader_instance *inst, void *pMemory) {
114    loader_free(inst ? &inst->alloc_callbacks : NULL, pMemory);
115}
116void *loader_instance_heap_realloc(const struct loader_instance *inst, void *pMemory, size_t orig_size, size_t size,
117                                   VkSystemAllocationScope allocation_scope) {
118    return loader_realloc(inst ? &inst->alloc_callbacks : NULL, pMemory, orig_size, size, allocation_scope);
119}
120
121void *loader_device_heap_alloc(const struct loader_device *dev, size_t size, VkSystemAllocationScope allocation_scope) {
122    return loader_alloc(dev ? &dev->alloc_callbacks : NULL, size, allocation_scope);
123}
124
125void *loader_device_heap_calloc(const struct loader_device *dev, size_t size, VkSystemAllocationScope allocation_scope) {
126    return loader_calloc(dev ? &dev->alloc_callbacks : NULL, size, allocation_scope);
127}
128
129void loader_device_heap_free(const struct loader_device *dev, void *pMemory) {
130    loader_free(dev ? &dev->alloc_callbacks : NULL, pMemory);
131}
132void *loader_device_heap_realloc(const struct loader_device *dev, void *pMemory, size_t orig_size, size_t size,
133                                 VkSystemAllocationScope allocation_scope) {
134    return loader_realloc(dev ? &dev->alloc_callbacks : NULL, pMemory, orig_size, size, allocation_scope);
135}
136
137void *loader_alloc_with_instance_fallback(const VkAllocationCallbacks *pAllocator, const struct loader_instance *inst, size_t size,
138                                          VkSystemAllocationScope allocation_scope) {
139    return loader_alloc(NULL != pAllocator ? pAllocator : &inst->alloc_callbacks, size, allocation_scope);
140}
141
142void *loader_calloc_with_instance_fallback(const VkAllocationCallbacks *pAllocator, const struct loader_instance *instance,
143                                           size_t size, VkSystemAllocationScope allocation_scope) {
144    return loader_calloc(NULL != pAllocator ? pAllocator : &instance->alloc_callbacks, size, allocation_scope);
145}
146
147void loader_free_with_instance_fallback(const VkAllocationCallbacks *pAllocator, const struct loader_instance *instance,
148                                        void *pMemory) {
149    loader_free(NULL != pAllocator ? pAllocator : &instance->alloc_callbacks, pMemory);
150}
151
152void *loader_realloc_with_instance_fallback(const VkAllocationCallbacks *pAllocator, const struct loader_instance *instance,
153                                            void *pMemory, size_t orig_size, size_t size,
154                                            VkSystemAllocationScope allocation_scope) {
155    return loader_realloc(NULL != pAllocator ? pAllocator : &instance->alloc_callbacks, pMemory, orig_size, size, allocation_scope);
156}
157