pvr: factor out framebuffer-specific code

Acked-by: Frank Binns <frank.binns@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38922>
This commit is contained in:
Erik Faye-Lund 2025-11-25 15:58:37 +01:00
parent 5c70230c49
commit b5400c8ddf
6 changed files with 315 additions and 280 deletions

View file

@ -35,6 +35,7 @@ pvr_files = files(
'pvr_device.c',
'pvr_dump_bo.c',
'pvr_dump_csb.c',
'pvr_framebuffer.c',
'pvr_free_list.c',
'pvr_formats.c',
'pvr_hw_pass.c',

View file

@ -45,6 +45,7 @@
#include "pvr_device_info.h"
#include "pvr_entrypoints.h"
#include "pvr_formats.h"
#include "pvr_framebuffer.h"
#include "pvr_hw_pass.h"
#include "pvr_image.h"
#include "pvr_job_common.h"

View file

@ -1868,73 +1868,8 @@ VkResult pvr_gpu_upload_pds(struct pvr_device *device,
return VK_SUCCESS;
}
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;
}
static void pvr_render_targets_fini(struct pvr_render_target *render_targets,
uint32_t render_targets_count)
void pvr_render_targets_fini(struct pvr_render_target *render_targets,
uint32_t render_targets_count)
{
for (uint32_t i = 0; i < render_targets_count; i++) {
pvr_render_targets_datasets_destroy(&render_targets[i]);
@ -1942,19 +1877,6 @@ static void pvr_render_targets_fini(struct pvr_render_target *render_targets,
}
}
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_spm_scratch_buffer_calc_required_size(
pass->hw_setup->renders,
pass->hw_setup->render_count,
pass->max_sample_count,
rstate->width,
rstate->height);
}
void pvr_render_state_cleanup(struct pvr_device *device,
const struct pvr_render_state *rstate)
{
@ -1975,206 +1897,6 @@ void pvr_render_state_cleanup(struct pvr_device *device,
vk_free(&device->vk.alloc, rstate->render_targets);
}
VkResult
pvr_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_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_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;
}
VkResult pvr_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_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_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, framebuffer->rstate);
/* the render state is freed with the framebuffer */
vk_object_base_finish(&framebuffer->base);
vk_free2(&device->vk.alloc, pAllocator, framebuffer);
}
void pvr_GetBufferMemoryRequirements2(
VkDevice _device,
const VkBufferMemoryRequirementsInfo2 *pInfo,

View file

@ -38,6 +38,7 @@ struct pvr_border_color_table;
struct pvr_device_static_clear_state;
struct pvr_instance;
struct pvr_queue;
struct pvr_render_target;
struct pvr_compute_query_shader {
struct pvr_suballoc_bo *usc_bo;
@ -228,4 +229,7 @@ void pvr_rstate_entry_add(struct pvr_device *device,
void pvr_rstate_entry_remove(struct pvr_device *device,
const struct pvr_render_state *rstate);
void pvr_render_targets_fini(struct pvr_render_target *render_targets,
uint32_t render_targets_count);
#endif /* PVR_DEVICE_H */

View file

@ -0,0 +1,306 @@
/*
* 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_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_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_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_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_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_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_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, framebuffer->rstate);
/* the render state is freed with the framebuffer */
vk_object_base_finish(&framebuffer->base);
vk_free2(&device->vk.alloc, pAllocator, framebuffer);
}

View file

@ -21,6 +21,7 @@
#include "vk_object.h"
#include "pvr_limits.h"
#include "pvr_macros.h"
struct pvr_render_target {
struct pvr_rt_dataset *rt_dataset[PVR_MAX_MULTIVIEW];