diff --git a/include/render/vulkan.h b/include/render/vulkan.h index 1d6e9949e..33d158dee 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -222,6 +222,13 @@ struct wlr_vk_render_buffer { uint32_t mem_count; VkImage image; + // Framebuffer and image view for rendering directly onto the buffer image, + // without any color transform. + struct { + struct wlr_vk_render_buffer_out out; + struct wlr_vk_render_format_setup *render_setup; + } linear; + // 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. @@ -246,6 +253,8 @@ struct wlr_vk_render_buffer { } two_pass; }; +bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffer, + const struct wlr_dmabuf_attributes *dmabuf, bool srgb); bool vulkan_setup_two_pass_framebuffer(struct wlr_vk_render_buffer *buffer, const struct wlr_dmabuf_attributes *dmabuf); diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index a950e2732..4cbb3c26c 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -1182,10 +1182,21 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend inv_eotf = WLR_COLOR_TRANSFER_FUNCTION_SRGB; } + bool using_linear_pathway = inv_eotf == WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR; bool using_srgb_pathway = inv_eotf == WLR_COLOR_TRANSFER_FUNCTION_SRGB && buffer->srgb.out.framebuffer != VK_NULL_HANDLE; + bool using_two_pass_pathway = !using_linear_pathway && !using_srgb_pathway; - if (!using_srgb_pathway) { + if (using_linear_pathway && !buffer->linear.out.image_view) { + struct wlr_dmabuf_attributes attribs; + wlr_buffer_get_dmabuf(buffer->wlr_buffer, &attribs); + if (!vulkan_setup_one_pass_framebuffer(buffer, &attribs, false)) { + wlr_log(WLR_ERROR, "Failed to set up blend image"); + return NULL; + } + } + + if (using_two_pass_pathway) { if (options != NULL && options->color_transform != NULL && !get_color_transform(options->color_transform, renderer)) { /* Try to create a new color transform */ @@ -1205,10 +1216,20 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend } } - struct wlr_vk_render_format_setup *render_setup = - using_srgb_pathway ? buffer->srgb.render_setup : buffer->two_pass.render_setup; - struct wlr_vk_render_buffer_out *buffer_out = - using_srgb_pathway ? &buffer->srgb.out : &buffer->two_pass.out; + struct wlr_vk_render_format_setup *render_setup; + struct wlr_vk_render_buffer_out *buffer_out; + if (using_two_pass_pathway) { + render_setup = buffer->two_pass.render_setup; + buffer_out = &buffer->two_pass.out; + } else if (using_srgb_pathway) { + render_setup = buffer->srgb.render_setup; + buffer_out = &buffer->srgb.out; + } else if (using_linear_pathway) { + render_setup = buffer->linear.render_setup; + buffer_out = &buffer->linear.out; + } else { + abort(); // unreachable + } struct wlr_vk_render_pass *pass = calloc(1, sizeof(*pass)); if (pass == NULL) { @@ -1217,7 +1238,7 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend wlr_render_pass_init(&pass->base, &render_pass_impl); pass->renderer = renderer; - pass->two_pass = !using_srgb_pathway; + pass->two_pass = using_two_pass_pathway; if (options != NULL && options->color_transform != NULL) { pass->color_transform = wlr_color_transform_ref(options->color_transform); } diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index 23f75d93e..a1a1bf6da 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -623,6 +623,7 @@ static void destroy_render_buffer(struct wlr_vk_render_buffer *buffer) { wlr_vk_error("vkQueueWaitIdle", res); } + finish_render_buffer_out(&buffer->linear.out, dev); finish_render_buffer_out(&buffer->srgb.out, dev); finish_render_buffer_out(&buffer->two_pass.out, dev); @@ -817,8 +818,8 @@ error: return false; } -static bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffer, - const struct wlr_dmabuf_attributes *dmabuf) { +bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffer, + const struct wlr_dmabuf_attributes *dmabuf, bool srgb) { struct wlr_vk_renderer *renderer = buffer->renderer; VkResult res; VkDevice dev = renderer->dev->dev; @@ -827,14 +828,18 @@ static bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffe renderer->dev, dmabuf->format); assert(fmt); - assert(fmt->format.vk_srgb); + VkFormat vk_fmt = srgb ? fmt->format.vk_srgb : fmt->format.vk; + assert(vk_fmt != VK_FORMAT_UNDEFINED); + + struct wlr_vk_render_buffer_out *out = srgb ? &buffer->srgb.out : &buffer->linear.out; + // Set up the srgb framebuffer by default; two-pass 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 = fmt->format.vk_srgb, + .format = vk_fmt, .components.r = VK_COMPONENT_SWIZZLE_IDENTITY, .components.g = VK_COMPONENT_SWIZZLE_IDENTITY, .components.b = VK_COMPONENT_SWIZZLE_IDENTITY, @@ -848,35 +853,43 @@ static bool vulkan_setup_one_pass_framebuffer(struct wlr_vk_render_buffer *buffe }, }; - res = vkCreateImageView(dev, &view_info, NULL, &buffer->srgb.out.image_view); + res = vkCreateImageView(dev, &view_info, NULL, &out->image_view); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateImageView failed", res); goto error; } - buffer->srgb.render_setup = find_or_create_render_setup( - renderer, &fmt->format, false); - if (!buffer->srgb.render_setup) { + struct wlr_vk_render_format_setup *render_setup = + find_or_create_render_setup(renderer, &fmt->format, false); + if (!render_setup) { goto error; } VkFramebufferCreateInfo fb_info = { .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, .attachmentCount = 1, - .pAttachments = &buffer->srgb.out.image_view, + .pAttachments = &out->image_view, .flags = 0u, .width = dmabuf->width, .height = dmabuf->height, .layers = 1u, - .renderPass = buffer->srgb.render_setup->render_pass, + .renderPass = render_setup->render_pass, }; - res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->srgb.out.framebuffer); + res = vkCreateFramebuffer(dev, &fb_info, NULL, &out->framebuffer); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateFramebuffer", res); goto error; } + + if (srgb) { + buffer->srgb.render_setup = render_setup; + } else { + buffer->linear.render_setup = render_setup; + } + return true; + error: // cleaning up everything is the caller's responsibility, // since it will need to do this anyway if framebuffer setup fails @@ -920,7 +933,7 @@ static struct wlr_vk_render_buffer *create_render_buffer( } if (using_mutable_srgb) { - if (!vulkan_setup_one_pass_framebuffer(buffer, &dmabuf)) { + if (!vulkan_setup_one_pass_framebuffer(buffer, &dmabuf, true)) { goto error; } } else {