render/vulkan: Dynamically create pipeline layouts

These will happen lazily when pipelines get created.
This commit is contained in:
Alexander Orzechowski 2023-06-17 21:21:31 -04:00
parent 3623005858
commit 8a387b5558
4 changed files with 148 additions and 145 deletions

View file

@ -123,7 +123,13 @@ const struct wlr_vk_format_modifier_props *vulkan_format_props_find_modifier(
struct wlr_vk_format_props *props, uint64_t mod, bool render); struct wlr_vk_format_props *props, uint64_t mod, bool render);
void vulkan_format_props_finish(struct wlr_vk_format_props *props); void vulkan_format_props_finish(struct wlr_vk_format_props *props);
struct wlr_vk_pipeline_layout_key {
const struct wlr_vk_format *ycbcr_format;
};
struct wlr_vk_pipeline_layout { struct wlr_vk_pipeline_layout {
struct wlr_vk_pipeline_layout_key key;
VkPipelineLayout vk; VkPipelineLayout vk;
VkDescriptorSetLayout ds; VkDescriptorSetLayout ds;
VkSampler sampler; VkSampler sampler;
@ -133,6 +139,8 @@ struct wlr_vk_pipeline_layout {
VkSamplerYcbcrConversion conversion; VkSamplerYcbcrConversion conversion;
VkFormat format; VkFormat format;
} ycbcr; } ycbcr;
struct wl_list link; // struct wlr_vk_renderer.pipeline_layouts
}; };
// Constants used to pick the color transform for the texture drawing // Constants used to pick the color transform for the texture drawing
@ -148,8 +156,8 @@ enum wlr_vk_shader_source {
}; };
struct wlr_vk_pipeline_key { struct wlr_vk_pipeline_key {
struct wlr_vk_pipeline_layout_key layout;
enum wlr_vk_shader_source source; enum wlr_vk_shader_source source;
struct wlr_vk_pipeline_layout *layout;
enum wlr_render_blend_mode blend_mode; enum wlr_render_blend_mode blend_mode;
// only used if source is texture // only used if source is texture
@ -160,6 +168,7 @@ struct wlr_vk_pipeline {
struct wlr_vk_pipeline_key key; struct wlr_vk_pipeline_key key;
VkPipeline vk; VkPipeline vk;
const struct wlr_vk_pipeline_layout *layout;
struct wlr_vk_render_format_setup *setup; struct wlr_vk_render_format_setup *setup;
struct wl_list link; // struct wlr_vk_render_format_setup struct wl_list link; // struct wlr_vk_render_format_setup
}; };
@ -168,7 +177,7 @@ struct wlr_vk_pipeline {
// and therefore also separate pipelines. // and therefore also separate pipelines.
struct wlr_vk_render_format_setup { struct wlr_vk_render_format_setup {
struct wl_list link; // wlr_vk_renderer.render_format_setups struct wl_list link; // wlr_vk_renderer.render_format_setups
VkFormat render_format; // used in renderpass const struct wlr_vk_format *render_format; // used in renderpass
VkRenderPass render_pass; VkRenderPass render_pass;
VkPipeline output_pipe; VkPipeline output_pipe;
@ -228,9 +237,7 @@ struct wlr_vk_renderer {
VkShaderModule quad_frag_module; VkShaderModule quad_frag_module;
VkShaderModule output_module; VkShaderModule output_module;
struct wlr_vk_pipeline_layout default_pipeline_layout; struct wl_list pipeline_layouts; // struct wlr_vk_pipeline_layout.link
size_t ycbcr_pipeline_layouts_len;
struct wlr_vk_pipeline_layout *ycbcr_pipeline_layouts;
// for blend->output subpass // for blend->output subpass
VkPipelineLayout output_pipe_layout; VkPipelineLayout output_pipe_layout;
@ -291,6 +298,9 @@ struct wlr_vk_vert_pcr_data {
struct wlr_vk_pipeline *setup_get_or_create_pipeline( struct wlr_vk_pipeline *setup_get_or_create_pipeline(
struct wlr_vk_render_format_setup *setup, struct wlr_vk_render_format_setup *setup,
const struct wlr_vk_pipeline_key *key); const struct wlr_vk_pipeline_key *key);
struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout(
struct wlr_vk_renderer *renderer,
const struct wlr_vk_pipeline_layout_key *key);
// Creates a vulkan renderer for the given device. // Creates a vulkan renderer for the given device.
struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev); struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev);
@ -344,9 +354,6 @@ struct wlr_vk_format_props *vulkan_format_props_from_drm(
struct wlr_vk_device *dev, uint32_t drm_format); struct wlr_vk_device *dev, uint32_t drm_format);
struct wlr_vk_renderer *vulkan_get_renderer(struct wlr_renderer *r); struct wlr_vk_renderer *vulkan_get_renderer(struct wlr_renderer *r);
struct wlr_vk_pipeline_layout *vulkan_get_pipeline_layout(struct wlr_vk_renderer *renderer,
const struct wlr_vk_format *format);
struct wlr_vk_command_buffer *vulkan_acquire_command_buffer( struct wlr_vk_command_buffer *vulkan_acquire_command_buffer(
struct wlr_vk_renderer *renderer); struct wlr_vk_renderer *renderer);
uint64_t vulkan_end_command_buffer(struct wlr_vk_command_buffer *cb, uint64_t vulkan_end_command_buffer(struct wlr_vk_command_buffer *cb,
@ -368,7 +375,6 @@ struct wlr_vk_texture {
VkImage image; VkImage image;
VkImageView image_view; VkImageView image_view;
const struct wlr_vk_format *format; const struct wlr_vk_format *format;
struct wlr_vk_pipeline_layout *pipeline_layout;
enum wlr_vk_texture_transform transform; enum wlr_vk_texture_transform transform;
VkDescriptorSet ds; VkDescriptorSet ds;
struct wlr_vk_descriptor_pool *ds_pool; struct wlr_vk_descriptor_pool *ds_pool;

View file

@ -404,7 +404,6 @@ error:
static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, static void render_pass_add_rect(struct wlr_render_pass *wlr_pass,
const struct wlr_render_rect_options *options) { const struct wlr_render_rect_options *options) {
struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass); struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass);
struct wlr_vk_renderer *renderer = pass->renderer;
VkCommandBuffer cb = pass->command_buffer->vk; VkCommandBuffer cb = pass->command_buffer->vk;
// Input color values are given in sRGB space, shader expects // Input color values are given in sRGB space, shader expects
@ -436,7 +435,7 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass,
pass->render_buffer->render_setup, pass->render_buffer->render_setup,
&(struct wlr_vk_pipeline_key) { &(struct wlr_vk_pipeline_key) {
.source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR, .source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR,
.layout = &renderer->default_pipeline_layout, .layout = { .ycbcr_format = NULL },
}); });
if (!pipe) { if (!pipe) {
pass->failed = true; pass->failed = true;
@ -450,9 +449,9 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass,
mat3_to_mat4(matrix, vert_pcr_data.mat4); mat3_to_mat4(matrix, vert_pcr_data.mat4);
bind_pipeline(pass, pipe->vk); bind_pipeline(pass, pipe->vk);
vkCmdPushConstants(cb, renderer->default_pipeline_layout.vk, vkCmdPushConstants(cb, pipe->layout->vk,
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data); VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data);
vkCmdPushConstants(cb, renderer->default_pipeline_layout.vk, vkCmdPushConstants(cb, pipe->layout->vk,
VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(float) * 4, VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(float) * 4,
linear_color); linear_color);
@ -546,21 +545,24 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass,
render_buffer->render_setup, render_buffer->render_setup,
&(struct wlr_vk_pipeline_key) { &(struct wlr_vk_pipeline_key) {
.source = WLR_VK_SHADER_SOURCE_TEXTURE, .source = WLR_VK_SHADER_SOURCE_TEXTURE,
.layout = texture->pipeline_layout, .layout = {
.ycbcr_format = texture->format->is_ycbcr ? texture->format : NULL,
},
.texture_transform = texture->transform, .texture_transform = texture->transform,
}); });
if (!pipe) { if (!pipe) {
pass->failed = true; pass->failed = true;
return;
} }
bind_pipeline(pass, pipe->vk); bind_pipeline(pass, pipe->vk);
vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS,
pipe->key.layout->vk, 0, 1, &texture->ds, 0, NULL); pipe->layout->vk, 0, 1, &texture->ds, 0, NULL);
vkCmdPushConstants(cb, pipe->key.layout->vk, vkCmdPushConstants(cb, pipe->layout->vk,
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data); VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data);
vkCmdPushConstants(cb, pipe->key.layout->vk, vkCmdPushConstants(cb, pipe->layout->vk,
VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(float), VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(float),
&alpha); &alpha);

View file

@ -56,7 +56,8 @@ struct wlr_vk_renderer *vulkan_get_renderer(struct wlr_renderer *wlr_renderer) {
} }
static struct wlr_vk_render_format_setup *find_or_create_render_setup( static struct wlr_vk_render_format_setup *find_or_create_render_setup(
struct wlr_vk_renderer *renderer, VkFormat format, bool has_blending_buffer); struct wlr_vk_renderer *renderer, const struct wlr_vk_format *format,
bool has_blending_buffer);
// https://www.w3.org/Graphics/Color/srgb // https://www.w3.org/Graphics/Color/srgb
static float color_to_linear(float non_linear) { static float color_to_linear(float non_linear) {
@ -793,7 +794,7 @@ static struct wlr_vk_render_buffer *create_render_buffer(
bool has_blending_buffer = !fmt->format.is_srgb; bool has_blending_buffer = !fmt->format.is_srgb;
buffer->render_setup = find_or_create_render_setup( buffer->render_setup = find_or_create_render_setup(
renderer, fmt->format.vk, has_blending_buffer); renderer, &fmt->format, has_blending_buffer);
if (!buffer->render_setup) { if (!buffer->render_setup) {
goto error; goto error;
} }
@ -1409,7 +1410,9 @@ static bool vulkan_render_subtexture_with_matrix(struct wlr_renderer *wlr_render
struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline( struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline(
renderer->current_render_buffer->render_setup, renderer->current_render_buffer->render_setup,
&(struct wlr_vk_pipeline_key) { &(struct wlr_vk_pipeline_key) {
.layout = texture->pipeline_layout, .layout = {
.ycbcr_format = texture->format->is_ycbcr ? texture->format : NULL,
},
.texture_transform = texture->transform, .texture_transform = texture->transform,
}); });
if (!pipe) { if (!pipe) {
@ -1422,7 +1425,7 @@ static bool vulkan_render_subtexture_with_matrix(struct wlr_renderer *wlr_render
} }
vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS,
pipe->key.layout->vk, 0, 1, &texture->ds, 0, NULL); pipe->layout->vk, 0, 1, &texture->ds, 0, NULL);
float final_matrix[9]; float final_matrix[9];
wlr_matrix_multiply(final_matrix, renderer->projection, matrix); wlr_matrix_multiply(final_matrix, renderer->projection, matrix);
@ -1435,9 +1438,9 @@ static bool vulkan_render_subtexture_with_matrix(struct wlr_renderer *wlr_render
vert_pcr_data.uv_size[0] = box->width / wlr_texture->width; vert_pcr_data.uv_size[0] = box->width / wlr_texture->width;
vert_pcr_data.uv_size[1] = box->height / wlr_texture->height; vert_pcr_data.uv_size[1] = box->height / wlr_texture->height;
vkCmdPushConstants(cb, pipe->key.layout->vk, vkCmdPushConstants(cb, pipe->layout->vk,
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data); VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data);
vkCmdPushConstants(cb, pipe->key.layout->vk, vkCmdPushConstants(cb, pipe->layout->vk,
VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(float), VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(float),
&alpha); &alpha);
vkCmdDraw(cb, 4, 1, 0, 0); vkCmdDraw(cb, 4, 1, 0, 0);
@ -1512,7 +1515,9 @@ static void vulkan_render_quad_with_matrix(struct wlr_renderer *wlr_renderer,
renderer->current_render_buffer->render_setup, renderer->current_render_buffer->render_setup,
&(struct wlr_vk_pipeline_key) { &(struct wlr_vk_pipeline_key) {
.source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR, .source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR,
.layout = &renderer->default_pipeline_layout, .layout = {
.ycbcr_format = NULL,
},
}); });
if (!pipe) { if (!pipe) {
return; return;
@ -1546,9 +1551,9 @@ static void vulkan_render_quad_with_matrix(struct wlr_renderer *wlr_renderer,
linear_color[2] = color_to_linear(color[2]); linear_color[2] = color_to_linear(color[2]);
linear_color[3] = color[3]; // no conversion for alpha linear_color[3] = color[3]; // no conversion for alpha
vkCmdPushConstants(cb, renderer->default_pipeline_layout.vk, vkCmdPushConstants(cb, pipe->layout->vk,
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data); VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data);
vkCmdPushConstants(cb, renderer->default_pipeline_layout.vk, vkCmdPushConstants(cb, pipe->layout->vk,
VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(float) * 4, VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(float) * 4,
linear_color); linear_color);
vkCmdDraw(cb, 4, 1, 0, 0); vkCmdDraw(cb, 4, 1, 0, 0);
@ -1578,15 +1583,6 @@ static uint32_t vulkan_preferred_read_format(
return dmabuf.format; return dmabuf.format;
} }
static void finish_pipeline_layout(struct wlr_vk_renderer *renderer,
struct wlr_vk_pipeline_layout *pipeline_layout) {
struct wlr_vk_device *dev = renderer->dev;
vkDestroyPipelineLayout(dev->dev, pipeline_layout->vk, NULL);
vkDestroyDescriptorSetLayout(dev->dev, pipeline_layout->ds, NULL);
vkDestroySampler(dev->dev, pipeline_layout->sampler, NULL);
vkDestroySamplerYcbcrConversion(dev->dev, pipeline_layout->ycbcr.conversion, NULL);
}
static void vulkan_destroy(struct wlr_renderer *wlr_renderer) { static void vulkan_destroy(struct wlr_renderer *wlr_renderer) {
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer); struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
struct wlr_vk_device *dev = renderer->dev; struct wlr_vk_device *dev = renderer->dev;
@ -1651,11 +1647,14 @@ static void vulkan_destroy(struct wlr_renderer *wlr_renderer) {
vkDestroyShaderModule(dev->dev, renderer->quad_frag_module, NULL); vkDestroyShaderModule(dev->dev, renderer->quad_frag_module, NULL);
vkDestroyShaderModule(dev->dev, renderer->output_module, NULL); vkDestroyShaderModule(dev->dev, renderer->output_module, NULL);
finish_pipeline_layout(renderer, &renderer->default_pipeline_layout); struct wlr_vk_pipeline_layout *pipeline_layout, *pipeline_layout_tmp;
for (size_t i = 0; i < renderer->ycbcr_pipeline_layouts_len; i++) { wl_list_for_each_safe(pipeline_layout, pipeline_layout_tmp,
finish_pipeline_layout(renderer, &renderer->ycbcr_pipeline_layouts[i]); &renderer->pipeline_layouts, link) {
vkDestroyPipelineLayout(dev->dev, pipeline_layout->vk, NULL);
vkDestroyDescriptorSetLayout(dev->dev, pipeline_layout->ds, NULL);
vkDestroySampler(dev->dev, pipeline_layout->sampler, NULL);
vkDestroySamplerYcbcrConversion(dev->dev, pipeline_layout->ycbcr.conversion, NULL);
} }
free(renderer->ycbcr_pipeline_layouts);
vkDestroySemaphore(dev->dev, renderer->timeline_semaphore, NULL); vkDestroySemaphore(dev->dev, renderer->timeline_semaphore, NULL);
vkDestroyPipelineLayout(dev->dev, renderer->output_pipe_layout, NULL); vkDestroyPipelineLayout(dev->dev, renderer->output_pipe_layout, NULL);
@ -1698,7 +1697,7 @@ static bool vulkan_read_pixels(struct wlr_renderer *wlr_renderer,
return false; return false;
} }
VkFormat dst_format = wlr_vk_format->vk; VkFormat dst_format = wlr_vk_format->vk;
VkFormat src_format = vk_renderer->current_render_buffer->render_setup->render_format; VkFormat src_format = vk_renderer->current_render_buffer->render_setup->render_format->vk;
VkFormatProperties dst_format_props = {0}, src_format_props = {0}; VkFormatProperties dst_format_props = {0}, src_format_props = {0};
vkGetPhysicalDeviceFormatProperties(vk_renderer->dev->phdev, dst_format, &dst_format_props); vkGetPhysicalDeviceFormatProperties(vk_renderer->dev->phdev, dst_format, &dst_format_props);
vkGetPhysicalDeviceFormatProperties(vk_renderer->dev->phdev, src_format, &src_format_props); vkGetPhysicalDeviceFormatProperties(vk_renderer->dev->phdev, src_format, &src_format_props);
@ -2094,9 +2093,22 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer,
return true; return true;
} }
static bool pipeline_layout_key_equals(
const struct wlr_vk_pipeline_layout_key *a,
const struct wlr_vk_pipeline_layout_key *b) {
assert(!a->ycbcr_format || a->ycbcr_format->is_ycbcr);
assert(!b->ycbcr_format || b->ycbcr_format->is_ycbcr);
if (a->ycbcr_format != b->ycbcr_format) {
return false;
}
return true;
}
static bool pipeline_key_equals(const struct wlr_vk_pipeline_key *a, static bool pipeline_key_equals(const struct wlr_vk_pipeline_key *a,
const struct wlr_vk_pipeline_key *b) { const struct wlr_vk_pipeline_key *b) {
if (a->layout != b->layout) { if (!pipeline_layout_key_equals(&a->layout, &b->layout)) {
return false; return false;
} }
@ -2128,15 +2140,22 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline(
} }
} }
struct wlr_vk_renderer *renderer = setup->renderer;
struct wlr_vk_pipeline_layout *pipeline_layout = get_or_create_pipeline_layout(
renderer, &key->layout);
if (!pipeline_layout) {
return NULL;
}
pipeline = calloc(1, sizeof(*pipeline)); pipeline = calloc(1, sizeof(*pipeline));
if (!pipeline) { if (!pipeline) {
return NULL; return NULL;
} }
struct wlr_vk_renderer *renderer = setup->renderer;
pipeline->setup = setup; pipeline->setup = setup;
pipeline->key = *key; pipeline->key = *key;
pipeline->layout = pipeline_layout;
VkResult res; VkResult res;
VkDevice dev = renderer->dev->dev; VkDevice dev = renderer->dev->dev;
@ -2246,7 +2265,7 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline(
VkGraphicsPipelineCreateInfo pinfo = { VkGraphicsPipelineCreateInfo pinfo = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.layout = key->layout->vk, .layout = pipeline_layout->vk,
.renderPass = setup->render_pass, .renderPass = setup->render_pass,
.subpass = 0, .subpass = 0,
.stageCount = 2, .stageCount = 2,
@ -2386,31 +2405,51 @@ static bool init_pipeline_layout(struct wlr_vk_renderer *renderer,
return true; return true;
} }
static bool init_ycbcr_pipeline_layout(struct wlr_vk_renderer *renderer, struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout(
struct wlr_vk_pipeline_layout *pipeline_layout, struct wlr_vk_renderer *renderer,
const struct wlr_vk_format *format) { const struct wlr_vk_pipeline_layout_key *key) {
VkResult res; struct wlr_vk_pipeline_layout *pipeline_layout;
wl_list_for_each(pipeline_layout, &renderer->pipeline_layouts, link) {
assert(format->is_ycbcr); if (pipeline_layout_key_equals(&pipeline_layout->key, key)) {
pipeline_layout->ycbcr.format = format->vk; return pipeline_layout;
}
VkSamplerYcbcrConversionCreateInfo conversion_create_info = {
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
.format = format->vk,
.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601,
.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
.xChromaOffset = VK_CHROMA_LOCATION_MIDPOINT,
.yChromaOffset = VK_CHROMA_LOCATION_MIDPOINT,
.chromaFilter = VK_FILTER_LINEAR,
};
res = vkCreateSamplerYcbcrConversion(renderer->dev->dev,
&conversion_create_info, NULL, &pipeline_layout->ycbcr.conversion);
if (res != VK_SUCCESS) {
wlr_vk_error("vkCreateSamplerYcbcrConversion", res);
return false;
} }
return init_pipeline_layout(renderer, pipeline_layout); pipeline_layout = calloc(1, sizeof(*pipeline_layout));
if (!pipeline_layout) {
return NULL;
}
pipeline_layout->key = *key;
VkResult res;
if (key->ycbcr_format) {
VkSamplerYcbcrConversionCreateInfo conversion_create_info = {
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
.format = key->ycbcr_format->vk,
.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601,
.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
.xChromaOffset = VK_CHROMA_LOCATION_MIDPOINT,
.yChromaOffset = VK_CHROMA_LOCATION_MIDPOINT,
.chromaFilter = VK_FILTER_LINEAR,
};
res = vkCreateSamplerYcbcrConversion(renderer->dev->dev,
&conversion_create_info, NULL, &pipeline_layout->ycbcr.conversion);
if (res != VK_SUCCESS) {
wlr_vk_error("vkCreateSamplerYcbcrConversion", res);
free(pipeline_layout);
return NULL;
}
}
if (!init_pipeline_layout(renderer, pipeline_layout)) {
free(pipeline_layout);
return NULL;
}
wl_list_insert(&renderer->pipeline_layouts, &pipeline_layout->link);
return pipeline_layout;
} }
// Creates static render data, such as sampler, layouts and shader modules // Creates static render data, such as sampler, layouts and shader modules
@ -2420,41 +2459,6 @@ static bool init_static_render_data(struct wlr_vk_renderer *renderer) {
VkResult res; VkResult res;
VkDevice dev = renderer->dev->dev; VkDevice dev = renderer->dev->dev;
if (!init_pipeline_layout(renderer, &renderer->default_pipeline_layout)) {
return false;
}
size_t ycbcr_formats_len = 0;
for (size_t i = 0; i < renderer->dev->format_prop_count; i++) {
struct wlr_vk_format_props *props = &renderer->dev->format_props[i];
if (renderer->dev->sampler_ycbcr_conversion && props->format.is_ycbcr) {
ycbcr_formats_len++;
}
}
if (ycbcr_formats_len > 0) {
renderer->ycbcr_pipeline_layouts =
calloc(ycbcr_formats_len, sizeof(*renderer->ycbcr_pipeline_layouts));
if (renderer->ycbcr_pipeline_layouts == NULL) {
return false;
}
for (size_t i = 0; i < renderer->dev->format_prop_count; i++) {
const struct wlr_vk_format *format = &renderer->dev->format_props[i].format;
if (!format->is_ycbcr) {
continue;
}
struct wlr_vk_pipeline_layout *pl =
&renderer->ycbcr_pipeline_layouts[renderer->ycbcr_pipeline_layouts_len];
if (!init_ycbcr_pipeline_layout(renderer, pl, format)) {
return false;
}
renderer->ycbcr_pipeline_layouts_len++;
}
}
if (!init_blend_to_output_layouts(renderer, &renderer->output_ds_layout, if (!init_blend_to_output_layouts(renderer, &renderer->output_ds_layout,
&renderer->output_pipe_layout)) { &renderer->output_pipe_layout)) {
return false; return false;
@ -2510,7 +2514,8 @@ static bool init_static_render_data(struct wlr_vk_renderer *renderer) {
} }
static struct wlr_vk_render_format_setup *find_or_create_render_setup( static struct wlr_vk_render_format_setup *find_or_create_render_setup(
struct wlr_vk_renderer *renderer, VkFormat format, bool has_blending_buffer) { struct wlr_vk_renderer *renderer, const struct wlr_vk_format *format,
bool has_blending_buffer) {
struct wlr_vk_render_format_setup *setup; struct wlr_vk_render_format_setup *setup;
wl_list_for_each(setup, &renderer->render_format_setups, link) { wl_list_for_each(setup, &renderer->render_format_setups, link) {
if (setup->render_format == format) { if (setup->render_format == format) {
@ -2544,7 +2549,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
}, },
{ {
.format = format, .format = format->vk,
.samples = VK_SAMPLE_COUNT_1_BIT, .samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE, .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
@ -2649,7 +2654,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
} }
} else { } else {
VkAttachmentDescription attachment = { VkAttachmentDescription attachment = {
.format = format, .format = format->vk,
.samples = VK_SAMPLE_COUNT_1_BIT, .samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE, .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
@ -2718,7 +2723,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){ if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){
.source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR, .source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR,
.layout = &renderer->default_pipeline_layout, .layout = { .ycbcr_format = NULL },
})) { })) {
goto error; goto error;
} }
@ -2726,7 +2731,7 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){ if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){
.source = WLR_VK_SHADER_SOURCE_TEXTURE, .source = WLR_VK_SHADER_SOURCE_TEXTURE,
.texture_transform = WLR_VK_TEXTURE_TRANSFORM_IDENTITY, .texture_transform = WLR_VK_TEXTURE_TRANSFORM_IDENTITY,
.layout = &renderer->default_pipeline_layout, .layout = {.ycbcr_format = NULL },
})) { })) {
goto error; goto error;
} }
@ -2734,18 +2739,24 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){ if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){
.source = WLR_VK_SHADER_SOURCE_TEXTURE, .source = WLR_VK_SHADER_SOURCE_TEXTURE,
.texture_transform = WLR_VK_TEXTURE_TRANSFORM_SRGB, .texture_transform = WLR_VK_TEXTURE_TRANSFORM_SRGB,
.layout = &renderer->default_pipeline_layout, .layout = {.ycbcr_format = NULL },
})) { })) {
goto error; goto error;
} }
for (size_t i = 0; i < renderer->ycbcr_pipeline_layouts_len; i++) { for (size_t i = 0; i < renderer->dev->format_prop_count; i++) {
if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){ const struct wlr_vk_format *format = &renderer->dev->format_props[i].format;
.source = WLR_VK_SHADER_SOURCE_TEXTURE, const struct wlr_vk_pipeline_layout_key layout = {
.texture_transform = WLR_VK_TEXTURE_TRANSFORM_SRGB, .ycbcr_format = format,
.layout = &renderer->ycbcr_pipeline_layouts[i], };
})) {
goto error; if (format->is_ycbcr) {
if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){
.texture_transform = WLR_VK_TEXTURE_TRANSFORM_SRGB,
.layout = layout
})) {
goto error;
}
} }
} }
@ -2774,6 +2785,7 @@ struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev
wl_list_init(&renderer->output_descriptor_pools); wl_list_init(&renderer->output_descriptor_pools);
wl_list_init(&renderer->render_format_setups); wl_list_init(&renderer->render_format_setups);
wl_list_init(&renderer->render_buffers); wl_list_init(&renderer->render_buffers);
wl_list_init(&renderer->pipeline_layouts);
if (!init_static_render_data(renderer)) { if (!init_static_render_data(renderer)) {
goto error; goto error;
@ -2858,26 +2870,6 @@ struct wlr_renderer *wlr_vk_renderer_create_with_drm_fd(int drm_fd) {
return vulkan_renderer_create_for_device(dev); return vulkan_renderer_create_for_device(dev);
} }
struct wlr_vk_pipeline_layout *vulkan_get_pipeline_layout(struct wlr_vk_renderer *renderer,
const struct wlr_vk_format *format) {
if (!format->is_ycbcr) {
return &renderer->default_pipeline_layout;
}
for (size_t i = 0; i < renderer->ycbcr_pipeline_layouts_len; i++) {
struct wlr_vk_pipeline_layout *pl = &renderer->ycbcr_pipeline_layouts[i];
if (pl->ycbcr.format == format->vk) {
return pl;
}
}
char *name = drmGetFormatName(format->drm);
wlr_log(WLR_ERROR, "No pipeline layout found for format %s (0x%08"PRIX32")",
name, format->drm);
free(name);
return NULL;
}
VkInstance wlr_vk_renderer_get_instance(struct wlr_renderer *renderer) { VkInstance wlr_vk_renderer_get_instance(struct wlr_renderer *renderer) {
struct wlr_vk_renderer *vk_renderer = vulkan_get_renderer(renderer); struct wlr_vk_renderer *vk_renderer = vulkan_get_renderer(renderer);
return vk_renderer->dev->instance->instance; return vk_renderer->dev->instance->instance;
@ -2902,6 +2894,6 @@ void wlr_vk_renderer_get_current_image_attribs(struct wlr_renderer *renderer,
struct wlr_vk_image_attribs *attribs) { struct wlr_vk_image_attribs *attribs) {
struct wlr_vk_renderer *vk_renderer = vulkan_get_renderer(renderer); struct wlr_vk_renderer *vk_renderer = vulkan_get_renderer(renderer);
attribs->image = vk_renderer->current_render_buffer->image; attribs->image = vk_renderer->current_render_buffer->image;
attribs->format = vk_renderer->current_render_buffer->render_setup->render_format; attribs->format = vk_renderer->current_render_buffer->render_setup->render_format->vk;
attribs->layout = VK_IMAGE_LAYOUT_UNDEFINED; attribs->layout = VK_IMAGE_LAYOUT_UNDEFINED;
} }

View file

@ -269,6 +269,15 @@ static bool vulkan_texture_init_view(struct wlr_vk_texture *texture) {
VkResult res; VkResult res;
VkDevice dev = texture->renderer->dev->dev; VkDevice dev = texture->renderer->dev->dev;
struct wlr_vk_pipeline_layout *pipeline_layout = get_or_create_pipeline_layout(
texture->renderer, &(struct wlr_vk_pipeline_layout_key) {
.ycbcr_format = texture->format->is_ycbcr ? texture->format : NULL,
});
if (!pipeline_layout) {
wlr_log(WLR_ERROR, "Failed to create a pipeline layout for a texture");
return NULL;
}
const struct wlr_pixel_format_info *format_info = const struct wlr_pixel_format_info *format_info =
drm_get_pixel_format_info(texture->format->drm); drm_get_pixel_format_info(texture->format->drm);
if (format_info != NULL) { if (format_info != NULL) {
@ -300,10 +309,10 @@ static bool vulkan_texture_init_view(struct wlr_vk_texture *texture) {
VkSamplerYcbcrConversionInfo ycbcr_conversion_info; VkSamplerYcbcrConversionInfo ycbcr_conversion_info;
if (texture->format->is_ycbcr) { if (texture->format->is_ycbcr) {
assert(texture->pipeline_layout->ycbcr.conversion != VK_NULL_HANDLE); assert(pipeline_layout->ycbcr.conversion != VK_NULL_HANDLE);
ycbcr_conversion_info = (VkSamplerYcbcrConversionInfo){ ycbcr_conversion_info = (VkSamplerYcbcrConversionInfo){
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, .sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
.conversion = texture->pipeline_layout->ycbcr.conversion, .conversion = pipeline_layout->ycbcr.conversion,
}; };
view_info.pNext = &ycbcr_conversion_info; view_info.pNext = &ycbcr_conversion_info;
} }
@ -314,7 +323,7 @@ static bool vulkan_texture_init_view(struct wlr_vk_texture *texture) {
return false; return false;
} }
texture->ds_pool = vulkan_alloc_texture_ds(texture->renderer, texture->pipeline_layout->ds, &texture->ds); texture->ds_pool = vulkan_alloc_texture_ds(texture->renderer, pipeline_layout->ds, &texture->ds);
if (!texture->ds_pool) { if (!texture->ds_pool) {
wlr_log(WLR_ERROR, "failed to allocate descriptor"); wlr_log(WLR_ERROR, "failed to allocate descriptor");
return false; return false;
@ -360,7 +369,6 @@ static struct wlr_texture *vulkan_texture_from_pixels(
} }
texture->format = &fmt->format; texture->format = &fmt->format;
texture->pipeline_layout = &renderer->default_pipeline_layout;
VkImageCreateInfo img_info = { VkImageCreateInfo img_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
@ -692,11 +700,6 @@ static struct wlr_vk_texture *vulkan_texture_from_dmabuf(
texture->transform = !texture->format->is_ycbcr && texture->format->is_srgb ? texture->transform = !texture->format->is_ycbcr && texture->format->is_srgb ?
WLR_VK_TEXTURE_TRANSFORM_IDENTITY : WLR_VK_TEXTURE_TRANSFORM_SRGB; WLR_VK_TEXTURE_TRANSFORM_IDENTITY : WLR_VK_TEXTURE_TRANSFORM_SRGB;
texture->pipeline_layout = vulkan_get_pipeline_layout(renderer, texture->format);
if (texture->pipeline_layout == NULL) {
goto error;
}
texture->image = vulkan_import_dmabuf(renderer, attribs, texture->image = vulkan_import_dmabuf(renderer, attribs,
texture->memories, &texture->mem_count, false); texture->memories, &texture->mem_count, false);
if (!texture->image) { if (!texture->image) {