mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-26 12:10:22 +01:00
v3dv: implement proper caching for partial clear pipelines
So far we have been caching the first pipeline we produced and always reusing that, which is obviously incorrect. This change implements a proper cache and also takes care of releasing the cached resources when the device is destroyed. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
This commit is contained in:
parent
c09c8c0ef3
commit
d6d8bfbb4a
3 changed files with 127 additions and 35 deletions
|
|
@ -1057,6 +1057,50 @@ init_device_dispatch(struct v3dv_device *device)
|
|||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
meta_color_clear_cache_hash(const void *key)
|
||||
{
|
||||
return _mesa_hash_data(key, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
static bool
|
||||
meta_color_clear_cache_compare(const void *key1, const void *key2)
|
||||
{
|
||||
return memcmp(key1, key2, sizeof(uint64_t)) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
init_device_meta(struct v3dv_device *device)
|
||||
{
|
||||
mtx_init(&device->meta.mtx, mtx_plain);
|
||||
|
||||
device->meta.color_clear.cache =
|
||||
_mesa_hash_table_create(NULL,
|
||||
meta_color_clear_cache_hash,
|
||||
meta_color_clear_cache_compare);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_device_meta(struct v3dv_device *device)
|
||||
{
|
||||
VkDevice _device = v3dv_device_to_handle(device);
|
||||
|
||||
mtx_destroy(&device->meta.mtx);
|
||||
|
||||
hash_table_foreach(device->meta.color_clear.cache, entry) {
|
||||
struct v3dv_meta_color_clear_pipeline *item = entry->data;
|
||||
v3dv_DestroyPipeline(_device, item->pipeline, &device->alloc);
|
||||
v3dv_DestroyRenderPass(_device, item->pass, &device->alloc);
|
||||
vk_free(&device->alloc, item);
|
||||
}
|
||||
_mesa_hash_table_destroy(device->meta.color_clear.cache, NULL);
|
||||
|
||||
if (device->meta.color_clear.playout) {
|
||||
v3dv_DestroyPipelineLayout(_device, device->meta.color_clear.playout,
|
||||
&device->alloc);
|
||||
}
|
||||
}
|
||||
|
||||
VkResult
|
||||
v3dv_CreateDevice(VkPhysicalDevice physicalDevice,
|
||||
const VkDeviceCreateInfo *pCreateInfo,
|
||||
|
|
@ -1157,6 +1201,7 @@ v3dv_CreateDevice(VkPhysicalDevice physicalDevice,
|
|||
}
|
||||
|
||||
init_device_dispatch(device);
|
||||
init_device_meta(device);
|
||||
|
||||
*pDevice = v3dv_device_to_handle(device);
|
||||
|
||||
|
|
@ -1177,6 +1222,7 @@ v3dv_DestroyDevice(VkDevice _device,
|
|||
v3dv_DeviceWaitIdle(_device);
|
||||
queue_finish(&device->queue);
|
||||
drmSyncobjDestroy(device->render_fd, device->last_job_sync);
|
||||
destroy_device_meta(device);
|
||||
|
||||
vk_free2(&default_alloc, pAllocator, device);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ create_color_clear_pipeline(struct v3dv_device *device,
|
|||
uint32_t rt_idx,
|
||||
uint32_t samples,
|
||||
VkRenderPass _pass,
|
||||
VkPipelineLayout *pipeline_layout,
|
||||
VkPipelineLayout pipeline_layout,
|
||||
VkPipeline *pipeline)
|
||||
{
|
||||
/* For now we only support clearing a framebuffer with a single attachment */
|
||||
|
|
@ -305,10 +305,6 @@ create_color_clear_pipeline(struct v3dv_device *device,
|
|||
.pAttachments = blend_att_state
|
||||
};
|
||||
|
||||
VkResult result = create_color_clear_pipeline_layout(device, pipeline_layout);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
return create_pipeline(device,
|
||||
pass,
|
||||
samples,
|
||||
|
|
@ -316,7 +312,7 @@ create_color_clear_pipeline(struct v3dv_device *device,
|
|||
&vi_state,
|
||||
&ds_state,
|
||||
&cb_state,
|
||||
*pipeline_layout,
|
||||
pipeline_layout,
|
||||
pipeline);
|
||||
}
|
||||
|
||||
|
|
@ -365,36 +361,76 @@ create_color_clear_render_pass(struct v3dv_device *device,
|
|||
&info, &device->alloc, pass);
|
||||
}
|
||||
|
||||
static VkResult
|
||||
ensure_color_clear_pipeline(struct v3dv_device *device,
|
||||
VkFormat format,
|
||||
uint32_t samples)
|
||||
static inline uint64_t
|
||||
get_color_clear_pipeline_cache_key(VkFormat format, uint32_t samples)
|
||||
{
|
||||
return ((uint64_t) samples) << 32 | format;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
get_color_clear_pipeline(struct v3dv_device *device,
|
||||
VkFormat format,
|
||||
uint32_t samples,
|
||||
struct v3dv_meta_color_clear_pipeline **pipeline)
|
||||
{
|
||||
/* FIXME: we need a pipeline per [format, samples], right now this
|
||||
* only works for the first combination we need.
|
||||
*/
|
||||
VkResult result = VK_SUCCESS;
|
||||
if (device->meta.color_clear.pipeline)
|
||||
|
||||
mtx_lock(&device->meta.mtx);
|
||||
if (!device->meta.color_clear.playout) {
|
||||
result =
|
||||
create_color_clear_pipeline_layout(device,
|
||||
&device->meta.color_clear.playout);
|
||||
}
|
||||
mtx_unlock(&device->meta.mtx);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
if (!device->meta.color_clear.pass) {
|
||||
result =
|
||||
create_color_clear_render_pass(device,
|
||||
format,
|
||||
samples,
|
||||
&device->meta.color_clear.pass);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
uint64_t key = get_color_clear_pipeline_cache_key(format, samples);
|
||||
mtx_lock(&device->meta.mtx);
|
||||
struct hash_entry *entry =
|
||||
_mesa_hash_table_search(device->meta.color_clear.cache, &key);
|
||||
if (entry) {
|
||||
mtx_unlock(&device->meta.mtx);
|
||||
*pipeline = entry->data;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
if (!device->meta.color_clear.pipeline) {
|
||||
result =
|
||||
create_color_clear_pipeline(device, 0 /* rt_idx*/, samples,
|
||||
device->meta.color_clear.pass,
|
||||
&device->meta.color_clear.playout,
|
||||
&device->meta.color_clear.pipeline);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
*pipeline = vk_zalloc2(&device->alloc, NULL, sizeof(**pipeline), 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
|
||||
|
||||
if (*pipeline == NULL)
|
||||
goto fail;
|
||||
|
||||
result = create_color_clear_render_pass(device,
|
||||
format,
|
||||
samples,
|
||||
&(*pipeline)->pass);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
result = create_color_clear_pipeline(device, 0 /* rt_idx*/, samples,
|
||||
(*pipeline)->pass,
|
||||
device->meta.color_clear.playout,
|
||||
&(*pipeline)->pipeline);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
_mesa_hash_table_insert(device->meta.color_clear.cache, &key, *pipeline);
|
||||
|
||||
mtx_unlock(&device->meta.mtx);
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail:
|
||||
mtx_unlock(&device->meta.mtx);
|
||||
|
||||
VkDevice _device = v3dv_device_to_handle(device);
|
||||
if (*pipeline) {
|
||||
if ((*pipeline)->pass)
|
||||
v3dv_DestroyRenderPass(_device, (*pipeline)->pass, &device->alloc);
|
||||
if ((*pipeline)->pipeline)
|
||||
v3dv_DestroyPipeline(_device, (*pipeline)->pipeline, &device->alloc);
|
||||
vk_free(&device->alloc, *pipeline);
|
||||
*pipeline = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -444,8 +480,12 @@ emit_color_clear_rect(struct v3dv_cmd_buffer *cmd_buffer,
|
|||
if (vk_format_is_depth_or_stencil(rt_format))
|
||||
rt_format = get_color_format_for_depth_stencil_format(rt_format);
|
||||
|
||||
if (ensure_color_clear_pipeline(device, rt_format, rt_samples) != VK_SUCCESS)
|
||||
struct v3dv_meta_color_clear_pipeline *pipeline = NULL;
|
||||
VkResult result =
|
||||
get_color_clear_pipeline(device, rt_format, rt_samples, &pipeline);
|
||||
if (result != VK_SUCCESS)
|
||||
return;
|
||||
assert(pipeline && pipeline->pipeline && pipeline->pass);
|
||||
|
||||
/* Store command buffer state for the current subpass before we interrupt
|
||||
* it to emit the color clear pass and then finish the job for the
|
||||
|
|
@ -508,7 +548,7 @@ emit_color_clear_rect(struct v3dv_cmd_buffer *cmd_buffer,
|
|||
|
||||
VkRenderPassBeginInfo rp_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||
.renderPass = device->meta.color_clear.pass,
|
||||
.renderPass = pipeline->pass,
|
||||
.framebuffer = fb,
|
||||
.renderArea = { .offset = { 0, 0 },
|
||||
.extent = { fb_info.width, fb_info.height } },
|
||||
|
|
@ -532,7 +572,7 @@ emit_color_clear_rect(struct v3dv_cmd_buffer *cmd_buffer,
|
|||
|
||||
v3dv_CmdBindPipeline(cmd_buffer_handle,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
device->meta.color_clear.pipeline);
|
||||
pipeline->pipeline);
|
||||
|
||||
const VkViewport viewport = {
|
||||
.x = rect->rect.offset.x,
|
||||
|
|
|
|||
|
|
@ -217,6 +217,12 @@ struct v3dv_queue {
|
|||
|
||||
void v3dv_queue_destroy_completed_noop_jobs(struct v3dv_queue *queue);
|
||||
|
||||
|
||||
struct v3dv_meta_color_clear_pipeline {
|
||||
VkPipeline pipeline;
|
||||
VkRenderPass pass;
|
||||
};
|
||||
|
||||
struct v3dv_device {
|
||||
VK_LOADER_DATA _loader_data;
|
||||
|
||||
|
|
@ -239,10 +245,10 @@ struct v3dv_device {
|
|||
|
||||
/* Resources used for meta operations */
|
||||
struct {
|
||||
mtx_t mtx;
|
||||
struct {
|
||||
VkPipelineLayout playout;
|
||||
VkPipeline pipeline;
|
||||
VkRenderPass pass;
|
||||
struct hash_table *cache; /* v3dv_meta_color_clear_pipeline */
|
||||
} color_clear;
|
||||
} meta;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue