• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2022 Imagination Technologies Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include <assert.h>
25 #include <stddef.h>
26 #include <stdint.h>
27 #include <vulkan/vulkan.h>
28 
29 #include "pvr_bo.h"
30 #include "pvr_private.h"
31 #include "pvr_types.h"
32 #include "pvr_winsys.h"
33 #include "vk_alloc.h"
34 #include "vk_log.h"
35 
pvr_bo_alloc_to_winsys_flags(uint64_t flags)36 static uint32_t pvr_bo_alloc_to_winsys_flags(uint64_t flags)
37 {
38    uint32_t ws_flags = 0;
39 
40    if (flags & PVR_BO_ALLOC_FLAG_CPU_ACCESS)
41       ws_flags |= PVR_WINSYS_BO_FLAG_CPU_ACCESS;
42 
43    if (flags & PVR_BO_ALLOC_FLAG_GPU_UNCACHED)
44       ws_flags |= PVR_WINSYS_BO_FLAG_GPU_UNCACHED;
45 
46    if (flags & PVR_BO_ALLOC_FLAG_PM_FW_PROTECT)
47       ws_flags |= PVR_WINSYS_BO_FLAG_PM_FW_PROTECT;
48 
49    if (flags & PVR_BO_ALLOC_FLAG_ZERO_ON_ALLOC)
50       ws_flags |= PVR_WINSYS_BO_FLAG_ZERO_ON_ALLOC;
51 
52    return ws_flags;
53 }
54 
55 /**
56  * \brief Helper interface to allocate a GPU buffer and map it to both host and
57  * device virtual memory. Host mapping is conditional and is controlled by
58  * flags.
59  *
60  * \param[in] device      Logical device pointer.
61  * \param[in] heap        Heap to allocate device virtual address from.
62  * \param[in] size        Size of buffer to allocate.
63  * \param[in] alignment   Required alignment of the allocation. Must be a power
64  *                        of two.
65  * \param[in] flags       Controls allocation, CPU and GPU mapping behavior
66  *                        using PVR_BO_ALLOC_FLAG_*.
67  * \param[out] pvr_bo_out On success output buffer is returned in this pointer.
68  * \return VK_SUCCESS on success, or error code otherwise.
69  *
70  * \sa #pvr_bo_free()
71  */
pvr_bo_alloc(struct pvr_device * device,struct pvr_winsys_heap * heap,uint64_t size,uint64_t alignment,uint64_t flags,struct pvr_bo ** const pvr_bo_out)72 VkResult pvr_bo_alloc(struct pvr_device *device,
73                       struct pvr_winsys_heap *heap,
74                       uint64_t size,
75                       uint64_t alignment,
76                       uint64_t flags,
77                       struct pvr_bo **const pvr_bo_out)
78 {
79    const uint32_t ws_flags = pvr_bo_alloc_to_winsys_flags(flags);
80    struct pvr_bo *pvr_bo;
81    pvr_dev_addr_t addr;
82    VkResult result;
83 
84    pvr_bo = vk_alloc(&device->vk.alloc,
85                      sizeof(*pvr_bo),
86                      8,
87                      VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
88    if (!pvr_bo)
89       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
90 
91    result = device->ws->ops->buffer_create(device->ws,
92                                            size,
93                                            alignment,
94                                            PVR_WINSYS_BO_TYPE_GPU,
95                                            ws_flags,
96                                            &pvr_bo->bo);
97    if (result != VK_SUCCESS)
98       goto err_vk_free;
99 
100    if (flags & PVR_BO_ALLOC_FLAG_CPU_MAPPED) {
101       void *map = device->ws->ops->buffer_map(pvr_bo->bo);
102       if (!map) {
103          result = VK_ERROR_MEMORY_MAP_FAILED;
104          goto err_buffer_destroy;
105       }
106    }
107 
108    pvr_bo->vma = device->ws->ops->heap_alloc(heap, size, alignment);
109    if (!pvr_bo->vma) {
110       result = VK_ERROR_OUT_OF_DEVICE_MEMORY;
111       goto err_buffer_unmap;
112    }
113 
114    addr = device->ws->ops->vma_map(pvr_bo->vma, pvr_bo->bo, 0, size);
115    if (!addr.addr) {
116       result = VK_ERROR_MEMORY_MAP_FAILED;
117       goto err_heap_free;
118    }
119 
120    *pvr_bo_out = pvr_bo;
121 
122    return VK_SUCCESS;
123 
124 err_heap_free:
125    device->ws->ops->heap_free(pvr_bo->vma);
126 
127 err_buffer_unmap:
128    if (flags & PVR_BO_ALLOC_FLAG_CPU_MAPPED)
129       device->ws->ops->buffer_unmap(pvr_bo->bo);
130 
131 err_buffer_destroy:
132    device->ws->ops->buffer_destroy(pvr_bo->bo);
133 
134 err_vk_free:
135    vk_free(&device->vk.alloc, pvr_bo);
136 
137    return result;
138 }
139 
140 /**
141  * \brief Interface to map the buffer into host virtual address space.
142  *
143  * Buffer should have been created with the #PVR_BO_ALLOC_FLAG_CPU_ACCESS
144  * flag. It should also not already be mapped or it should have been unmapped
145  * using #pvr_bo_cpu_unmap() before mapping again.
146  *
147  * \param[in] device Logical device pointer.
148  * \param[in] pvr_bo Buffer to map.
149  * \return Valid host virtual address on success, or NULL otherwise.
150  *
151  * \sa #pvr_bo_alloc(), #PVR_BO_ALLOC_FLAG_CPU_MAPPED
152  */
pvr_bo_cpu_map(struct pvr_device * device,struct pvr_bo * pvr_bo)153 void *pvr_bo_cpu_map(struct pvr_device *device, struct pvr_bo *pvr_bo)
154 {
155    assert(!pvr_bo->bo->map);
156 
157    return device->ws->ops->buffer_map(pvr_bo->bo);
158 }
159 
160 /**
161  * \brief Interface to unmap the buffer from host virtual address space.
162  *
163  * Buffer should have a valid mapping, created either using #pvr_bo_cpu_map() or
164  * by passing #PVR_BO_ALLOC_FLAG_CPU_MAPPED flag to #pvr_bo_alloc() at
165  * allocation time.
166  *
167  * Buffer can be remapped using #pvr_bo_cpu_map().
168  *
169  * \param[in] device Logical device pointer.
170  * \param[in] pvr_bo Buffer to unmap.
171  */
pvr_bo_cpu_unmap(struct pvr_device * device,struct pvr_bo * pvr_bo)172 void pvr_bo_cpu_unmap(struct pvr_device *device, struct pvr_bo *pvr_bo)
173 {
174    assert(pvr_bo->bo->map);
175    device->ws->ops->buffer_unmap(pvr_bo->bo);
176 }
177 
178 /**
179  * \brief Interface to free the buffer object.
180  *
181  * \param[in] device Logical device pointer.
182  * \param[in] pvr_bo Buffer to free.
183  *
184  * \sa #pvr_bo_alloc()
185  */
pvr_bo_free(struct pvr_device * device,struct pvr_bo * pvr_bo)186 void pvr_bo_free(struct pvr_device *device, struct pvr_bo *pvr_bo)
187 {
188    if (!pvr_bo)
189       return;
190 
191    device->ws->ops->vma_unmap(pvr_bo->vma);
192    device->ws->ops->heap_free(pvr_bo->vma);
193 
194    if (pvr_bo->bo->map)
195       device->ws->ops->buffer_unmap(pvr_bo->bo);
196 
197    device->ws->ops->buffer_destroy(pvr_bo->bo);
198 
199    vk_free(&device->vk.alloc, pvr_bo);
200 }
201