From e443434876b6a76e89c8553e02a0d9a225e5f63b Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Sun, 7 Jan 2024 08:42:45 -0500 Subject: [PATCH] render/vulkan: create plain framebuffers on demand This change makes it possible to support both the direct srgb-format pipeline and indirect (color-managed, or non-srgb-format) pipeline for the same render buffer. --- include/render/vulkan.h | 48 ++++++-- render/vulkan/pass.c | 63 +++++++--- render/vulkan/renderer.c | 260 ++++++++++++++++++++++++--------------- 3 files changed, 240 insertions(+), 131 deletions(-) diff --git a/include/render/vulkan.h b/include/render/vulkan.h index b9c22420..e57db3d7 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -187,6 +187,7 @@ struct wlr_vk_pipeline { struct wlr_vk_render_format_setup { struct wl_list link; // wlr_vk_renderer.render_format_setups const struct wlr_vk_format *render_format; // used in renderpass + bool use_blending_buffer; VkRenderPass render_pass; VkPipeline output_pipe_srgb; @@ -201,24 +202,44 @@ struct wlr_vk_render_buffer { struct wlr_buffer *wlr_buffer; struct wlr_addon addon; struct wlr_vk_renderer *renderer; - struct wlr_vk_render_format_setup *render_setup; struct wl_list link; // wlr_vk_renderer.buffers - VkImage image; - VkImageView image_view; - VkFramebuffer framebuffer; - uint32_t mem_count; VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES]; - bool transitioned; - - VkImage blend_image; - VkImageView blend_image_view; - VkDeviceMemory blend_memory; - VkDescriptorSet blend_descriptor_set; - struct wlr_vk_descriptor_pool *blend_attachment_pool; - bool blend_transitioned; + uint32_t mem_count; + VkImage image; + + // Framebuffer and image view for rendering directly onto the buffer image. + // This requires that the image support an _SRGB VkFormat, and does + // not work with color transforms. + struct { + struct wlr_vk_render_format_setup *render_setup; + VkImageView image_view; + VkFramebuffer framebuffer; + bool transitioned; + } srgb; + + // Framebuffer, image view, and blending image to render indirectly + // onto the buffer image. This works for general image types and permits + // color transforms. + struct { + struct wlr_vk_render_format_setup *render_setup; + + VkImageView image_view; + VkFramebuffer framebuffer; + bool transitioned; + + VkImage blend_image; + VkImageView blend_image_view; + VkDeviceMemory blend_memory; + VkDescriptorSet blend_descriptor_set; + struct wlr_vk_descriptor_pool *blend_attachment_pool; + bool blend_transitioned; + } plain; }; +bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer, + const struct wlr_dmabuf_attributes *dmabuf); + struct wlr_vk_command_buffer { VkCommandBuffer vk; bool recording; @@ -351,6 +372,7 @@ struct wlr_vk_render_pass { VkPipeline bound_pipeline; float projection[9]; bool failed; + bool srgb_pathway; // if false, rendering via intermediate blending buffer }; struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *renderer, diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index 42141df6..f8fccf5e 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -87,7 +87,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { assert(stage_cb != NULL); renderer->stage.cb = NULL; - if (render_buffer->blend_image) { + if (!pass->srgb_pathway) { // Apply output shader to map blend image to actual output image vkCmdNextSubpass(render_cb->vk, VK_SUBPASS_CONTENTS_INLINE); @@ -109,14 +109,14 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { }; mat3_to_mat4(final_matrix, vert_pcr_data.mat4); - bind_pipeline(pass, render_buffer->render_setup->output_pipe_srgb); + bind_pipeline(pass, render_buffer->plain.render_setup->output_pipe_srgb); vkCmdPushConstants(render_cb->vk, renderer->output_pipe_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data); vkCmdPushConstants(render_cb->vk, renderer->output_pipe_layout, VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(frag_pcr_data), &frag_pcr_data); VkDescriptorSet ds[] = { - render_buffer->blend_descriptor_set, // set 0 + render_buffer->plain.blend_descriptor_set, // set 0 renderer->output_ds_lut3d_dummy, // set 1 }; size_t ds_len = sizeof(ds) / sizeof(ds[0]); @@ -218,26 +218,30 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { // also add acquire/release barriers for the current render buffer VkImageLayout src_layout = VK_IMAGE_LAYOUT_GENERAL; - if (!render_buffer->transitioned) { - src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED; - render_buffer->transitioned = true; - } - - if (render_buffer->blend_image) { + if (pass->srgb_pathway) { + if (!render_buffer->srgb.transitioned) { + src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED; + render_buffer->srgb.transitioned = true; + } + } else { + if (!render_buffer->plain.transitioned) { + src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED; + render_buffer->plain.transitioned = true; + } // The render pass changes the blend image layout from // color attachment to read only, so on each frame, before // the render pass starts, we change it back VkImageLayout blend_src_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - if (!render_buffer->blend_transitioned) { + if (!render_buffer->plain.blend_transitioned) { blend_src_layout = VK_IMAGE_LAYOUT_UNDEFINED; - render_buffer->blend_transitioned = true; + render_buffer->plain.blend_transitioned = true; } VkImageMemoryBarrier blend_acq_barrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = render_buffer->blend_image, + .image = render_buffer->plain.blend_image, .oldLayout = blend_src_layout, .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, .srcAccessMask = VK_ACCESS_SHADER_READ_BIT, @@ -435,7 +439,7 @@ error: static void render_pass_mark_box_updated(struct wlr_vk_render_pass *pass, const struct wlr_box *box) { - if (!pass->render_buffer->blend_image) { + if (pass->srgb_pathway) { return; } @@ -495,8 +499,11 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, proj); wlr_matrix_multiply(matrix, pass->projection, matrix); + struct wlr_vk_render_format_setup *setup = pass->srgb_pathway ? + pass->render_buffer->srgb.render_setup : + pass->render_buffer->plain.render_setup; struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline( - pass->render_buffer->render_setup, + setup, &(struct wlr_vk_pipeline_key) { .source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR, .layout = { .ycbcr_format = NULL }, @@ -560,7 +567,6 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, const struct wlr_render_texture_options *options) { struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass); struct wlr_vk_renderer *renderer = pass->renderer; - struct wlr_vk_render_buffer *render_buffer = pass->render_buffer; VkCommandBuffer cb = pass->command_buffer->vk; struct wlr_vk_texture *texture = vulkan_get_texture(options->texture); @@ -605,8 +611,11 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, }; mat3_to_mat4(matrix, vert_pcr_data.mat4); + struct wlr_vk_render_format_setup *setup = pass->srgb_pathway ? + pass->render_buffer->srgb.render_setup : + pass->render_buffer->plain.render_setup; struct wlr_vk_pipeline *pipe = setup_get_or_create_pipeline( - render_buffer->render_setup, + setup, &(struct wlr_vk_pipeline_key) { .source = WLR_VK_SHADER_SOURCE_TEXTURE, .layout = { @@ -672,12 +681,25 @@ static const struct wlr_render_pass_impl render_pass_impl = { struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *renderer, struct wlr_vk_render_buffer *buffer) { + bool using_srgb_pathway = buffer->srgb.framebuffer != VK_NULL_HANDLE; + + if (!using_srgb_pathway && !buffer->plain.image_view) { + struct wlr_dmabuf_attributes attribs; + wlr_buffer_get_dmabuf(buffer->wlr_buffer, &attribs); + if (!vulkan_setup_plain_framebuffer(buffer, &attribs)) { + wlr_log(WLR_ERROR, "Failed to set up blend image"); + return NULL; + } + } + struct wlr_vk_render_pass *pass = calloc(1, sizeof(*pass)); if (pass == NULL) { return NULL; } + wlr_render_pass_init(&pass->base, &render_pass_impl); pass->renderer = renderer; + pass->srgb_pathway = using_srgb_pathway; rect_union_init(&pass->updated_region); @@ -713,10 +735,15 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend VkRenderPassBeginInfo rp_info = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .renderArea = rect, - .renderPass = buffer->render_setup->render_pass, - .framebuffer = buffer->framebuffer, .clearValueCount = 0, }; + if (pass->srgb_pathway) { + rp_info.renderPass = buffer->srgb.render_setup->render_pass; + rp_info.framebuffer = buffer->srgb.framebuffer; + } else { + rp_info.renderPass = buffer->plain.render_setup->render_pass; + rp_info.framebuffer = buffer->plain.framebuffer; + } vkCmdBeginRenderPass(cb->vk, &rp_info, VK_SUBPASS_CONTENTS_INLINE); vkCmdSetViewport(cb->vk, 0, 1, &(VkViewport){ diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index 43959918..871cf94b 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -571,20 +571,22 @@ static void destroy_render_buffer(struct wlr_vk_render_buffer *buffer) { wlr_vk_error("vkQueueWaitIdle", res); } - vkDestroyFramebuffer(dev, buffer->framebuffer, NULL); - vkDestroyImageView(dev, buffer->image_view, NULL); - vkDestroyImage(dev, buffer->image, NULL); + vkDestroyFramebuffer(dev, buffer->srgb.framebuffer, NULL); + vkDestroyImageView(dev, buffer->srgb.image_view, NULL); - for (size_t i = 0u; i < buffer->mem_count; ++i) { - vkFreeMemory(dev, buffer->memories[i], NULL); + vkDestroyFramebuffer(dev, buffer->plain.framebuffer, NULL); + vkDestroyImageView(dev, buffer->plain.image_view, NULL); + vkDestroyImage(dev, buffer->plain.blend_image, NULL); + vkFreeMemory(dev, buffer->plain.blend_memory, NULL); + vkDestroyImageView(dev, buffer->plain.blend_image_view, NULL); + if (buffer->plain.blend_attachment_pool) { + vulkan_free_ds(buffer->renderer, buffer->plain.blend_attachment_pool, + buffer->plain.blend_descriptor_set); } - vkDestroyImage(dev, buffer->blend_image, NULL); - vkFreeMemory(dev, buffer->blend_memory, NULL); - vkDestroyImageView(dev, buffer->blend_image_view, NULL); - if (buffer->blend_attachment_pool) { - vulkan_free_ds(buffer->renderer, buffer->blend_attachment_pool, - buffer->blend_descriptor_set); + vkDestroyImage(dev, buffer->image, NULL); + for (size_t i = 0u; i < buffer->mem_count; ++i) { + vkFreeMemory(dev, buffer->memories[i], NULL); } free(buffer); @@ -600,11 +602,46 @@ static struct wlr_addon_interface render_buffer_addon_impl = { .destroy = handle_render_buffer_destroy, }; -static bool setup_blend_image(struct wlr_vk_renderer *renderer, - struct wlr_vk_render_buffer *buffer, int32_t width, int32_t height) { +bool vulkan_setup_plain_framebuffer(struct wlr_vk_render_buffer *buffer, + const struct wlr_dmabuf_attributes *dmabuf) { + struct wlr_vk_renderer *renderer = buffer->renderer; VkResult res; VkDevice dev = renderer->dev->dev; + const struct wlr_vk_format_props *fmt = vulkan_format_props_from_drm( + renderer->dev, dmabuf->format); + assert(fmt); + + VkImageViewCreateInfo view_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .image = buffer->image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = fmt->format.vk, + .components.r = VK_COMPONENT_SWIZZLE_IDENTITY, + .components.g = VK_COMPONENT_SWIZZLE_IDENTITY, + .components.b = VK_COMPONENT_SWIZZLE_IDENTITY, + .components.a = VK_COMPONENT_SWIZZLE_IDENTITY, + .subresourceRange = (VkImageSubresourceRange) { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + + res = vkCreateImageView(dev, &view_info, NULL, &buffer->plain.image_view); + if (res != VK_SUCCESS) { + wlr_vk_error("vkCreateImageView failed", res); + goto error; + } + + buffer->plain.render_setup = find_or_create_render_setup( + renderer, &fmt->format, true); + if (!buffer->plain.render_setup) { + goto error; + } + // Set up an extra 16F buffer on which to do linear blending, // and afterwards to render onto the target VkImageCreateInfo img_info = { @@ -617,18 +654,18 @@ static bool setup_blend_image(struct wlr_vk_renderer *renderer, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .tiling = VK_IMAGE_TILING_OPTIMAL, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .extent = (VkExtent3D) { width, height, 1 }, + .extent = (VkExtent3D) { dmabuf->width, dmabuf->height, 1 }, .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, }; - res = vkCreateImage(dev, &img_info, NULL, &buffer->blend_image); + res = vkCreateImage(dev, &img_info, NULL, &buffer->plain.blend_image); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateImage failed", res); goto error; } VkMemoryRequirements mem_reqs; - vkGetImageMemoryRequirements(dev, buffer->blend_image, &mem_reqs); + vkGetImageMemoryRequirements(dev, buffer->plain.blend_image, &mem_reqs); int mem_type_index = vulkan_find_mem_type(renderer->dev, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, mem_reqs.memoryTypeBits); @@ -643,13 +680,13 @@ static bool setup_blend_image(struct wlr_vk_renderer *renderer, .memoryTypeIndex = mem_type_index, }; - res = vkAllocateMemory(dev, &mem_info, NULL, &buffer->blend_memory); + res = vkAllocateMemory(dev, &mem_info, NULL, &buffer->plain.blend_memory); if (res != VK_SUCCESS) { wlr_vk_error("vkAllocatorMemory failed", res); goto error; } - res = vkBindImageMemory(dev, buffer->blend_image, buffer->blend_memory, 0); + res = vkBindImageMemory(dev, buffer->plain.blend_image, buffer->plain.blend_memory, 0); if (res != VK_SUCCESS) { wlr_vk_error("vkBindMemory failed", res); goto error; @@ -657,7 +694,7 @@ static bool setup_blend_image(struct wlr_vk_renderer *renderer, VkImageViewCreateInfo blend_view_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .image = buffer->blend_image, + .image = buffer->plain.blend_image, .viewType = VK_IMAGE_VIEW_TYPE_2D, .format = img_info.format, .components.r = VK_COMPONENT_SWIZZLE_IDENTITY, @@ -673,83 +710,81 @@ static bool setup_blend_image(struct wlr_vk_renderer *renderer, }, }; - res = vkCreateImageView(dev, &blend_view_info, NULL, &buffer->blend_image_view); + res = vkCreateImageView(dev, &blend_view_info, NULL, &buffer->plain.blend_image_view); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateImageView failed", res); goto error; } - buffer->blend_attachment_pool = vulkan_alloc_blend_ds(renderer, - &buffer->blend_descriptor_set); - if (!buffer->blend_attachment_pool) { + buffer->plain.blend_attachment_pool = vulkan_alloc_blend_ds(renderer, + &buffer->plain.blend_descriptor_set); + if (!buffer->plain.blend_attachment_pool) { wlr_log(WLR_ERROR, "failed to allocate descriptor"); goto error; } VkDescriptorImageInfo ds_attach_info = { .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - .imageView = buffer->blend_image_view, + .imageView = buffer->plain.blend_image_view, .sampler = VK_NULL_HANDLE, }; VkWriteDescriptorSet ds_write = { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, - .dstSet = buffer->blend_descriptor_set, + .dstSet = buffer->plain.blend_descriptor_set, .dstBinding = 0, .pImageInfo = &ds_attach_info, }; vkUpdateDescriptorSets(dev, 1, &ds_write, 0, NULL); + + VkImageView attachments[2] = { + buffer->plain.blend_image_view, + buffer->plain.image_view + }; + VkFramebufferCreateInfo fb_info = { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .attachmentCount = 2, + .pAttachments = attachments, + .flags = 0u, + .width = dmabuf->width, + .height = dmabuf->height, + .layers = 1u, + .renderPass = buffer->plain.render_setup->render_pass, + }; + + res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->plain.framebuffer); + if (res != VK_SUCCESS) { + wlr_vk_error("vkCreateFramebuffer", res); + goto error; + } + return true; error: - // cleaning up blend_attachment_pool, blend_descriptor_set, blend_image, - // blend_memory, and blend_image_view is the caller's responsibility, + // cleaning up everything is the caller's responsibility, // since it will need to do this anyway if framebuffer setup fails return false; } -static struct wlr_vk_render_buffer *create_render_buffer( - struct wlr_vk_renderer *renderer, struct wlr_buffer *wlr_buffer) { +static bool vulkan_setup_srgb_framebuffer(struct wlr_vk_render_buffer *buffer, + const struct wlr_dmabuf_attributes *dmabuf) { + struct wlr_vk_renderer *renderer = buffer->renderer; VkResult res; VkDevice dev = renderer->dev->dev; - struct wlr_vk_render_buffer *buffer = calloc(1, sizeof(*buffer)); - if (buffer == NULL) { - wlr_log_errno(WLR_ERROR, "Allocation failed"); - return NULL; - } - buffer->wlr_buffer = wlr_buffer; - buffer->renderer = renderer; - - struct wlr_dmabuf_attributes dmabuf = {0}; - if (!wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) { - goto error; - } - - wlr_log(WLR_DEBUG, "vulkan create_render_buffer: %.4s, %dx%d", - (const char*) &dmabuf.format, dmabuf.width, dmabuf.height); - - bool using_mutable_srgb = false; - buffer->image = vulkan_import_dmabuf(renderer, &dmabuf, - buffer->memories, &buffer->mem_count, true, &using_mutable_srgb); - if (!buffer->image) { - goto error; - } - const struct wlr_vk_format_props *fmt = vulkan_format_props_from_drm( - renderer->dev, dmabuf.format); - if (fmt == NULL) { - wlr_log(WLR_ERROR, "Unsupported pixel format %"PRIx32 " (%.4s)", - dmabuf.format, (const char*) &dmabuf.format); - goto error; - } + renderer->dev, dmabuf->format); + assert(fmt); + assert(fmt->format.vk_srgb); + // Set up the srgb framebuffer by default; plain framebuffer and + // blending image will be set up later if necessary VkImageViewCreateInfo view_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .image = buffer->image, .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = using_mutable_srgb ? fmt->format.vk_srgb : fmt->format.vk, + .format = fmt->format.vk_srgb, .components.r = VK_COMPONENT_SWIZZLE_IDENTITY, .components.g = VK_COMPONENT_SWIZZLE_IDENTITY, .components.b = VK_COMPONENT_SWIZZLE_IDENTITY, @@ -763,73 +798,96 @@ static struct wlr_vk_render_buffer *create_render_buffer( }, }; - res = vkCreateImageView(dev, &view_info, NULL, &buffer->image_view); + res = vkCreateImageView(dev, &view_info, NULL, &buffer->srgb.image_view); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateImageView failed", res); goto error; } - bool has_blending_buffer = !using_mutable_srgb; - - buffer->render_setup = find_or_create_render_setup( - renderer, &fmt->format, has_blending_buffer); - if (!buffer->render_setup) { + buffer->srgb.render_setup = find_or_create_render_setup( + renderer, &fmt->format, false); + if (!buffer->srgb.render_setup) { goto error; } - VkImageView attachments[2] = {0}; - uint32_t attachment_count = 0; - - if (has_blending_buffer) { - if (!setup_blend_image(renderer, buffer, dmabuf.width, dmabuf.height)) { - goto error; - } - attachments[attachment_count++] = buffer->blend_image_view; - } - attachments[attachment_count++] = buffer->image_view; - VkFramebufferCreateInfo fb_info = { .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - .attachmentCount = attachment_count, - .pAttachments = attachments, + .attachmentCount = 1, + .pAttachments = &buffer->srgb.image_view, .flags = 0u, - .width = dmabuf.width, - .height = dmabuf.height, + .width = dmabuf->width, + .height = dmabuf->height, .layers = 1u, - .renderPass = buffer->render_setup->render_pass, + .renderPass = buffer->srgb.render_setup->render_pass, }; - res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->framebuffer); + res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->srgb.framebuffer); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateFramebuffer", res); goto error; } + return true; +error: + // cleaning up everything is the caller's responsibility, + // since it will need to do this anyway if framebuffer setup fails + return false; +} - +static struct wlr_vk_render_buffer *create_render_buffer( + struct wlr_vk_renderer *renderer, struct wlr_buffer *wlr_buffer) { + struct wlr_vk_render_buffer *buffer = calloc(1, sizeof(*buffer)); + if (buffer == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return NULL; + } + buffer->wlr_buffer = wlr_buffer; + buffer->renderer = renderer; wlr_addon_init(&buffer->addon, &wlr_buffer->addons, renderer, &render_buffer_addon_impl); wl_list_insert(&renderer->render_buffers, &buffer->link); - return buffer; + struct wlr_dmabuf_attributes dmabuf = {0}; + if (!wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) { + goto error; + } -error: - if (buffer->blend_attachment_pool) { - vulkan_free_ds(buffer->renderer, buffer->blend_attachment_pool, - buffer->blend_descriptor_set); + wlr_log(WLR_DEBUG, "vulkan create_render_buffer: %.4s, %dx%d", + (const char*) &dmabuf.format, dmabuf.width, dmabuf.height); + + bool using_mutable_srgb = false; + buffer->image = vulkan_import_dmabuf(renderer, &dmabuf, + buffer->memories, &buffer->mem_count, true, &using_mutable_srgb); + if (!buffer->image) { + goto error; } - vkDestroyImage(dev, buffer->blend_image, NULL); - vkFreeMemory(dev, buffer->blend_memory, NULL); - vkDestroyImageView(dev, buffer->blend_image_view, NULL); - vkDestroyFramebuffer(dev, buffer->framebuffer, NULL); - vkDestroyImageView(dev, buffer->image_view, NULL); - vkDestroyImage(dev, buffer->image, NULL); - for (size_t i = 0u; i < buffer->mem_count; ++i) { - vkFreeMemory(dev, buffer->memories[i], NULL); + const struct wlr_vk_format_props *fmt = vulkan_format_props_from_drm( + renderer->dev, dmabuf.format); + if (fmt == NULL) { + wlr_log(WLR_ERROR, "Unsupported pixel format %"PRIx32 " (%.4s)", + dmabuf.format, (const char*) &dmabuf.format); + goto error; + } + + if (using_mutable_srgb) { + if (!vulkan_setup_srgb_framebuffer(buffer, &dmabuf)) { + goto error; + } + } else { + // Set up the plain framebuffer & blending image + if (!vulkan_setup_plain_framebuffer(buffer, &dmabuf)) { + goto error; + } + } + + return buffer; + +error: + if (buffer) { + destroy_render_buffer(buffer); } wlr_dmabuf_attributes_finish(&dmabuf); - free(buffer); return NULL; } @@ -2061,10 +2119,11 @@ static bool init_static_render_data(struct wlr_vk_renderer *renderer) { static struct wlr_vk_render_format_setup *find_or_create_render_setup( struct wlr_vk_renderer *renderer, const struct wlr_vk_format *format, - bool has_blending_buffer) { + bool use_blending_buffer) { struct wlr_vk_render_format_setup *setup; wl_list_for_each(setup, &renderer->render_format_setups, link) { - if (setup->render_format == format) { + if (setup->render_format == format && + setup->use_blending_buffer == use_blending_buffer) { return setup; } } @@ -2076,13 +2135,14 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup( } setup->render_format = format; + setup->use_blending_buffer = use_blending_buffer; setup->renderer = renderer; wl_list_init(&setup->pipelines); VkDevice dev = renderer->dev->dev; VkResult res; - if (has_blending_buffer) { + if (use_blending_buffer) { VkAttachmentDescription attachments[2] = { { .format = VK_FORMAT_R16G16B16A16_SFLOAT,