mirror of https://gitlab.freedesktop.org/mesa/mesa
231 lines
7.1 KiB
C
231 lines
7.1 KiB
C
/*
|
|
* Copyright © 2022 Imagination Technologies Ltd.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <vulkan/vulkan.h>
|
|
|
|
#include "pvr_bo.h"
|
|
#include "pvr_private.h"
|
|
#include "pvr_types.h"
|
|
#include "pvr_winsys.h"
|
|
#include "vk_alloc.h"
|
|
#include "vk_log.h"
|
|
|
|
static uint32_t pvr_bo_alloc_to_winsys_flags(uint64_t flags)
|
|
{
|
|
uint32_t ws_flags = 0;
|
|
|
|
if (flags & (PVR_BO_ALLOC_FLAG_CPU_ACCESS | PVR_BO_ALLOC_FLAG_CPU_MAPPED))
|
|
ws_flags |= PVR_WINSYS_BO_FLAG_CPU_ACCESS;
|
|
|
|
if (flags & PVR_BO_ALLOC_FLAG_GPU_UNCACHED)
|
|
ws_flags |= PVR_WINSYS_BO_FLAG_GPU_UNCACHED;
|
|
|
|
if (flags & PVR_BO_ALLOC_FLAG_PM_FW_PROTECT)
|
|
ws_flags |= PVR_WINSYS_BO_FLAG_PM_FW_PROTECT;
|
|
|
|
if (flags & PVR_BO_ALLOC_FLAG_ZERO_ON_ALLOC)
|
|
ws_flags |= PVR_WINSYS_BO_FLAG_ZERO_ON_ALLOC;
|
|
|
|
return ws_flags;
|
|
}
|
|
|
|
/**
|
|
* \brief Helper interface to allocate a GPU buffer and map it to both host and
|
|
* device virtual memory. Host mapping is conditional and is controlled by
|
|
* flags.
|
|
*
|
|
* \param[in] device Logical device pointer.
|
|
* \param[in] heap Heap to allocate device virtual address from.
|
|
* \param[in] size Size of buffer to allocate.
|
|
* \param[in] alignment Required alignment of the allocation. Must be a power
|
|
* of two.
|
|
* \param[in] flags Controls allocation, CPU and GPU mapping behavior
|
|
* using PVR_BO_ALLOC_FLAG_*.
|
|
* \param[out] pvr_bo_out On success output buffer is returned in this pointer.
|
|
* \return VK_SUCCESS on success, or error code otherwise.
|
|
*
|
|
* \sa #pvr_bo_free()
|
|
*/
|
|
VkResult 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)
|
|
{
|
|
const uint32_t ws_flags = pvr_bo_alloc_to_winsys_flags(flags);
|
|
struct pvr_bo *pvr_bo;
|
|
pvr_dev_addr_t addr;
|
|
VkResult result;
|
|
|
|
pvr_bo = vk_alloc(&device->vk.alloc,
|
|
sizeof(*pvr_bo),
|
|
8,
|
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
if (!pvr_bo)
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
result = device->ws->ops->buffer_create(device->ws,
|
|
size,
|
|
alignment,
|
|
PVR_WINSYS_BO_TYPE_GPU,
|
|
ws_flags,
|
|
&pvr_bo->bo);
|
|
if (result != VK_SUCCESS)
|
|
goto err_vk_free;
|
|
|
|
if (flags & PVR_BO_ALLOC_FLAG_CPU_MAPPED) {
|
|
void *map = device->ws->ops->buffer_map(pvr_bo->bo);
|
|
if (!map) {
|
|
result = VK_ERROR_MEMORY_MAP_FAILED;
|
|
goto err_buffer_destroy;
|
|
}
|
|
}
|
|
|
|
pvr_bo->vma = device->ws->ops->heap_alloc(heap, size, alignment);
|
|
if (!pvr_bo->vma) {
|
|
result = VK_ERROR_OUT_OF_DEVICE_MEMORY;
|
|
goto err_buffer_unmap;
|
|
}
|
|
|
|
addr = device->ws->ops->vma_map(pvr_bo->vma, pvr_bo->bo, 0, size);
|
|
if (!addr.addr) {
|
|
result = VK_ERROR_MEMORY_MAP_FAILED;
|
|
goto err_heap_free;
|
|
}
|
|
|
|
*pvr_bo_out = pvr_bo;
|
|
|
|
return VK_SUCCESS;
|
|
|
|
err_heap_free:
|
|
device->ws->ops->heap_free(pvr_bo->vma);
|
|
|
|
err_buffer_unmap:
|
|
if (flags & PVR_BO_ALLOC_FLAG_CPU_MAPPED)
|
|
device->ws->ops->buffer_unmap(pvr_bo->bo);
|
|
|
|
err_buffer_destroy:
|
|
device->ws->ops->buffer_destroy(pvr_bo->bo);
|
|
|
|
err_vk_free:
|
|
vk_free(&device->vk.alloc, pvr_bo);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \brief Interface to map the buffer into host virtual address space.
|
|
*
|
|
* Buffer should have been created with the #PVR_BO_ALLOC_FLAG_CPU_ACCESS
|
|
* flag. It should also not already be mapped or it should have been unmapped
|
|
* using #pvr_bo_cpu_unmap() before mapping again.
|
|
*
|
|
* \param[in] device Logical device pointer.
|
|
* \param[in] pvr_bo Buffer to map.
|
|
* \return Valid host virtual address on success, or NULL otherwise.
|
|
*
|
|
* \sa #pvr_bo_alloc(), #PVR_BO_ALLOC_FLAG_CPU_MAPPED
|
|
*/
|
|
void *pvr_bo_cpu_map(struct pvr_device *device, struct pvr_bo *pvr_bo)
|
|
{
|
|
assert(!pvr_bo->bo->map);
|
|
|
|
return device->ws->ops->buffer_map(pvr_bo->bo);
|
|
}
|
|
|
|
/**
|
|
* \brief Interface to unmap the buffer from host virtual address space.
|
|
*
|
|
* Buffer should have a valid mapping, created either using #pvr_bo_cpu_map() or
|
|
* by passing #PVR_BO_ALLOC_FLAG_CPU_MAPPED flag to #pvr_bo_alloc() at
|
|
* allocation time.
|
|
*
|
|
* Buffer can be remapped using #pvr_bo_cpu_map().
|
|
*
|
|
* \param[in] device Logical device pointer.
|
|
* \param[in] pvr_bo Buffer to unmap.
|
|
*/
|
|
void pvr_bo_cpu_unmap(struct pvr_device *device, struct pvr_bo *pvr_bo)
|
|
{
|
|
struct pvr_winsys_bo *bo = pvr_bo->bo;
|
|
|
|
assert(bo->map);
|
|
|
|
#if defined(HAVE_VALGRIND)
|
|
if (!bo->vbits)
|
|
bo->vbits = vk_alloc(&device->vk.alloc,
|
|
bo->size,
|
|
8,
|
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
if (bo->vbits)
|
|
VALGRIND_GET_VBITS(bo->map, bo->vbits, bo->size);
|
|
else
|
|
mesa_loge("Failed to alloc vbits storage; expect bad valgrind results.");
|
|
#endif /* defined(HAVE_VALGRIND) */
|
|
|
|
device->ws->ops->buffer_unmap(bo);
|
|
}
|
|
|
|
/**
|
|
* \brief Interface to free the buffer object.
|
|
*
|
|
* \param[in] device Logical device pointer.
|
|
* \param[in] pvr_bo Buffer to free.
|
|
*
|
|
* \sa #pvr_bo_alloc()
|
|
*/
|
|
void pvr_bo_free(struct pvr_device *device, struct pvr_bo *pvr_bo)
|
|
{
|
|
if (!pvr_bo)
|
|
return;
|
|
|
|
#if defined(HAVE_VALGRIND)
|
|
vk_free(&device->vk.alloc, pvr_bo->bo->vbits);
|
|
#endif /* defined(HAVE_VALGRIND) */
|
|
|
|
device->ws->ops->vma_unmap(pvr_bo->vma);
|
|
device->ws->ops->heap_free(pvr_bo->vma);
|
|
|
|
if (pvr_bo->bo->map)
|
|
device->ws->ops->buffer_unmap(pvr_bo->bo);
|
|
|
|
device->ws->ops->buffer_destroy(pvr_bo->bo);
|
|
|
|
vk_free(&device->vk.alloc, pvr_bo);
|
|
}
|
|
|
|
#if defined(HAVE_VALGRIND)
|
|
void *pvr_bo_cpu_map_unchanged(struct pvr_device *device, struct pvr_bo *pvr_bo)
|
|
{
|
|
void *ret = pvr_bo_cpu_map(device, pvr_bo);
|
|
if (ret)
|
|
VALGRIND_SET_VBITS(pvr_bo->bo->map, pvr_bo->bo->vbits, pvr_bo->bo->size);
|
|
|
|
return ret;
|
|
}
|
|
#endif /* defined(HAVE_VALGRIND) */
|