mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-19 22:18:18 +02:00
When creating frame buffers the alloc callbacks are used in the host
allocations, those same alloc callbacks need to be used when freeing
those allocations but are missing in some places causing the CTS to
report memory leaks in certain test cases.
Fixes: 146364ab9f ("pvr: add support for VK_KHR_dynamic_rendering")
fix:
dEQP-VK.api.object_management.alloc_callback_fail.framebuffer
dEQP-VK.api.object_management.single_alloc_callbacks.framebuffer
Signed-off-by: Nick Hamilton <nick.hamilton@imgtec.com>
Reviewed-by: Frank Binns <frank.binns@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/39960>
307 lines
9.8 KiB
C
307 lines
9.8 KiB
C
/*
|
|
* Copyright © 2022 Imagination Technologies Ltd.
|
|
*
|
|
* based in part on anv driver which is:
|
|
* Copyright © 2015 Intel Corporation
|
|
*
|
|
* based in part on v3dv driver which is:
|
|
* Copyright © 2019 Raspberry Pi
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include "pvr_framebuffer.h"
|
|
|
|
#include "vk_util.h"
|
|
|
|
#include "hwdef/pvr_hw_utils.h"
|
|
|
|
#include "pvr_cmd_buffer.h"
|
|
#include "pvr_csb.h"
|
|
#include "pvr_device.h"
|
|
#include "pvr_entrypoints.h"
|
|
#include "pvr_hw_pass.h"
|
|
#include "pvr_image.h"
|
|
#include "pvr_pass.h"
|
|
#include "pvr_physical_device.h"
|
|
#include "pvr_rt_dataset.h"
|
|
#include "pvr_spm.h"
|
|
|
|
static VkResult
|
|
pvr_render_state_create_ppp_state(struct pvr_device *device,
|
|
struct pvr_render_state *rstate)
|
|
{
|
|
const uint32_t cache_line_size =
|
|
pvr_get_slc_cache_line_size(&device->pdevice->dev_info);
|
|
uint32_t ppp_state[3];
|
|
VkResult result;
|
|
|
|
pvr_csb_pack (&ppp_state[0], TA_STATE_HEADER, header) {
|
|
header.pres_terminate = true;
|
|
}
|
|
|
|
pvr_csb_pack (&ppp_state[1], TA_STATE_TERMINATE0, term0) {
|
|
term0.clip_right =
|
|
DIV_ROUND_UP(
|
|
rstate->width,
|
|
ROGUE_TA_STATE_TERMINATE0_CLIP_RIGHT_BLOCK_SIZE_IN_PIXELS) -
|
|
1;
|
|
term0.clip_bottom =
|
|
DIV_ROUND_UP(
|
|
rstate->height,
|
|
ROGUE_TA_STATE_TERMINATE0_CLIP_BOTTOM_BLOCK_SIZE_IN_PIXELS) -
|
|
1;
|
|
}
|
|
|
|
pvr_csb_pack (&ppp_state[2], TA_STATE_TERMINATE1, term1) {
|
|
term1.render_target = 0;
|
|
term1.clip_left = 0;
|
|
}
|
|
|
|
result = pvr_gpu_upload(device,
|
|
device->heaps.general_heap,
|
|
ppp_state,
|
|
sizeof(ppp_state),
|
|
cache_line_size,
|
|
&rstate->ppp_state_bo);
|
|
if (result != VK_SUCCESS)
|
|
return result;
|
|
|
|
/* Calculate the size of PPP state in dwords. */
|
|
rstate->ppp_state_size = sizeof(ppp_state) / sizeof(uint32_t);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
static bool pvr_render_targets_init(struct pvr_render_target *render_targets,
|
|
uint32_t render_targets_count)
|
|
{
|
|
uint32_t i;
|
|
|
|
for (i = 0; i < render_targets_count; i++) {
|
|
if (pthread_mutex_init(&render_targets[i].mutex, NULL))
|
|
goto err_mutex_destroy;
|
|
}
|
|
|
|
return true;
|
|
|
|
err_mutex_destroy:
|
|
while (i--)
|
|
pthread_mutex_destroy(&render_targets[i].mutex);
|
|
|
|
return false;
|
|
}
|
|
|
|
VkResult
|
|
pvr_arch_render_state_setup(struct pvr_device *device,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
struct pvr_render_state *rstate,
|
|
uint32_t render_count,
|
|
const struct pvr_renderpass_hwsetup_render *renders)
|
|
{
|
|
struct pvr_spm_bgobj_state *spm_bgobj_state_per_render;
|
|
struct pvr_spm_eot_state *spm_eot_state_per_render;
|
|
struct pvr_render_target *render_targets;
|
|
uint32_t render_targets_count;
|
|
VkResult result;
|
|
|
|
render_targets_count =
|
|
PVR_RENDER_TARGETS_PER_FRAMEBUFFER(&device->pdevice->dev_info);
|
|
|
|
VK_MULTIALLOC(ma);
|
|
vk_multialloc_add(&ma,
|
|
&render_targets,
|
|
__typeof__(*render_targets),
|
|
render_targets_count);
|
|
vk_multialloc_add(&ma,
|
|
&spm_eot_state_per_render,
|
|
__typeof__(*spm_eot_state_per_render),
|
|
render_count);
|
|
vk_multialloc_add(&ma,
|
|
&spm_bgobj_state_per_render,
|
|
__typeof__(*spm_bgobj_state_per_render),
|
|
render_count);
|
|
|
|
if (!vk_multialloc_zalloc2(&ma,
|
|
&device->vk.alloc,
|
|
pAllocator,
|
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)) {
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
}
|
|
|
|
rstate->render_targets = render_targets;
|
|
rstate->render_targets_count = render_targets_count;
|
|
if (!pvr_render_targets_init(rstate->render_targets, render_targets_count)) {
|
|
result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
goto err_free_render_targets;
|
|
}
|
|
|
|
assert(rstate->scratch_buffer_size);
|
|
result = pvr_spm_scratch_buffer_get_buffer(device,
|
|
rstate->scratch_buffer_size,
|
|
&rstate->scratch_buffer);
|
|
if (result != VK_SUCCESS)
|
|
goto err_finish_render_targets;
|
|
|
|
result = pvr_render_state_create_ppp_state(device, rstate);
|
|
if (result != VK_SUCCESS)
|
|
goto err_release_scratch_buffer;
|
|
|
|
for (uint32_t i = 0; i < render_count; i++) {
|
|
result = pvr_arch_spm_init_eot_state(device,
|
|
&spm_eot_state_per_render[i],
|
|
rstate,
|
|
&renders[i]);
|
|
if (result != VK_SUCCESS)
|
|
goto err_finish_eot_state;
|
|
|
|
result = pvr_arch_spm_init_bgobj_state(device,
|
|
&spm_bgobj_state_per_render[i],
|
|
rstate,
|
|
&renders[i]);
|
|
if (result != VK_SUCCESS)
|
|
goto err_finish_bgobj_state;
|
|
|
|
continue;
|
|
|
|
err_finish_bgobj_state:
|
|
pvr_spm_finish_eot_state(device, &spm_eot_state_per_render[i]);
|
|
|
|
for (uint32_t j = 0; j < i; j++)
|
|
pvr_spm_finish_bgobj_state(device, &spm_bgobj_state_per_render[j]);
|
|
|
|
err_finish_eot_state:
|
|
for (uint32_t j = 0; j < i; j++)
|
|
pvr_spm_finish_eot_state(device, &spm_eot_state_per_render[j]);
|
|
|
|
goto err_free_ppp_state_bo;
|
|
}
|
|
|
|
rstate->render_count = render_count;
|
|
rstate->spm_eot_state_per_render = spm_eot_state_per_render;
|
|
rstate->spm_bgobj_state_per_render = spm_bgobj_state_per_render;
|
|
|
|
return VK_SUCCESS;
|
|
|
|
err_free_ppp_state_bo:
|
|
pvr_bo_suballoc_free(rstate->ppp_state_bo);
|
|
|
|
err_release_scratch_buffer:
|
|
pvr_spm_scratch_buffer_release(device, rstate->scratch_buffer);
|
|
|
|
err_finish_render_targets:
|
|
pvr_render_targets_fini(rstate->render_targets, render_targets_count);
|
|
|
|
err_free_render_targets:
|
|
vk_free2(&device->vk.alloc, pAllocator, rstate->render_targets);
|
|
|
|
return result;
|
|
}
|
|
|
|
static inline uint64_t
|
|
pvr_render_pass_get_scratch_buffer_size(struct pvr_device *device,
|
|
const struct pvr_render_pass *pass,
|
|
const struct pvr_render_state *rstate)
|
|
{
|
|
return pvr_arch_spm_scratch_buffer_calc_required_size(
|
|
pass->hw_setup->renders,
|
|
pass->hw_setup->render_count,
|
|
pass->max_sample_count,
|
|
rstate->width,
|
|
rstate->height);
|
|
}
|
|
|
|
VkResult
|
|
PVR_PER_ARCH(CreateFramebuffer)(VkDevice _device,
|
|
const VkFramebufferCreateInfo *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
VkFramebuffer *pFramebuffer)
|
|
{
|
|
VK_FROM_HANDLE(pvr_render_pass, pass, pCreateInfo->renderPass);
|
|
VK_FROM_HANDLE(pvr_device, device, _device);
|
|
const VkFramebufferAttachmentsCreateInfoKHR *pImageless;
|
|
struct pvr_framebuffer *framebuffer;
|
|
struct pvr_image_view **attachments;
|
|
struct pvr_render_state *rstate;
|
|
VkResult result;
|
|
|
|
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO);
|
|
|
|
pImageless = vk_find_struct_const(pCreateInfo->pNext,
|
|
FRAMEBUFFER_ATTACHMENTS_CREATE_INFO);
|
|
|
|
VK_MULTIALLOC(ma);
|
|
vk_multialloc_add(&ma, &framebuffer, __typeof__(*framebuffer), 1);
|
|
vk_multialloc_add(&ma, &rstate, __typeof__(*rstate), 1);
|
|
vk_multialloc_add(&ma,
|
|
&attachments,
|
|
__typeof__(*attachments),
|
|
pCreateInfo->attachmentCount);
|
|
|
|
if (!vk_multialloc_zalloc2(&ma,
|
|
&device->vk.alloc,
|
|
pAllocator,
|
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT))
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
vk_object_base_init(&device->vk,
|
|
&framebuffer->base,
|
|
VK_OBJECT_TYPE_FRAMEBUFFER);
|
|
|
|
framebuffer->attachments = attachments;
|
|
if (!pImageless)
|
|
framebuffer->attachment_count = pCreateInfo->attachmentCount;
|
|
else
|
|
framebuffer->attachment_count = pImageless->attachmentImageInfoCount;
|
|
for (uint32_t i = 0; i < framebuffer->attachment_count; i++) {
|
|
if (!pImageless) {
|
|
framebuffer->attachments[i] =
|
|
pvr_image_view_from_handle(pCreateInfo->pAttachments[i]);
|
|
} else {
|
|
assert(i < pImageless->attachmentImageInfoCount);
|
|
}
|
|
}
|
|
|
|
rstate->width = pCreateInfo->width;
|
|
rstate->height = pCreateInfo->height;
|
|
rstate->layers = pCreateInfo->layers;
|
|
rstate->scratch_buffer_size =
|
|
pvr_render_pass_get_scratch_buffer_size(device, pass, rstate);
|
|
|
|
result = pvr_arch_render_state_setup(device,
|
|
pAllocator,
|
|
rstate,
|
|
pass->hw_setup->render_count,
|
|
pass->hw_setup->renders);
|
|
if (result != VK_SUCCESS)
|
|
goto err_free_framebuffer;
|
|
|
|
framebuffer->rstate = rstate;
|
|
|
|
*pFramebuffer = pvr_framebuffer_to_handle(framebuffer);
|
|
|
|
return VK_SUCCESS;
|
|
|
|
err_free_framebuffer:
|
|
vk_object_base_finish(&framebuffer->base);
|
|
vk_free2(&device->vk.alloc, pAllocator, framebuffer);
|
|
|
|
return result;
|
|
}
|
|
|
|
void PVR_PER_ARCH(DestroyFramebuffer)(VkDevice _device,
|
|
VkFramebuffer _fb,
|
|
const VkAllocationCallbacks *pAllocator)
|
|
{
|
|
VK_FROM_HANDLE(pvr_framebuffer, framebuffer, _fb);
|
|
VK_FROM_HANDLE(pvr_device, device, _device);
|
|
|
|
if (!framebuffer)
|
|
return;
|
|
|
|
pvr_render_state_cleanup(device, pAllocator, framebuffer->rstate);
|
|
/* the render state is freed with the framebuffer */
|
|
|
|
vk_object_base_finish(&framebuffer->base);
|
|
vk_free2(&device->vk.alloc, pAllocator, framebuffer);
|
|
}
|