}
}
+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,
}
init_device_dispatch(device);
+ init_device_meta(device);
*pDevice = v3dv_device_to_handle(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);
}
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 */
.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,
&vi_state,
&ds_state,
&cb_state,
- *pipeline_layout,
+ pipeline_layout,
pipeline);
}
&info, &device->alloc, pass);
}
+static inline uint64_t
+get_color_clear_pipeline_cache_key(VkFormat format, uint32_t samples)
+{
+ return ((uint64_t) samples) << 32 | format;
+}
+
static VkResult
-ensure_color_clear_pipeline(struct v3dv_device *device,
- VkFormat format,
- uint32_t samples)
+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)
- return result;
- if (!device->meta.color_clear.pass) {
+ mtx_lock(&device->meta.mtx);
+ if (!device->meta.color_clear.playout) {
result =
- create_color_clear_render_pass(device,
- format,
- samples,
- &device->meta.color_clear.pass);
- if (result != VK_SUCCESS)
- return 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.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;
+ 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;
+ }
+
+ *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;
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
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 } },
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,