mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-11-25 22:25:58 +01:00
render/vulkan: allow rendering to non-8-bit buffers
This is implemented by a two-subpass rendering scheme; the first subpass draws (and blends) onto a linear R16G16B16A16_SFLOAT buffer, while the second subpass performs linear->srgb conversion, writing onto the actual output buffer.
This commit is contained in:
parent
8cdc4b7a31
commit
10dd416694
5 changed files with 651 additions and 90 deletions
|
@ -140,6 +140,7 @@ struct wlr_vk_render_format_setup {
|
||||||
VkPipeline tex_srgb_pipe;
|
VkPipeline tex_srgb_pipe;
|
||||||
VkPipeline tex_nv12_pipe;
|
VkPipeline tex_nv12_pipe;
|
||||||
VkPipeline quad_pipe;
|
VkPipeline quad_pipe;
|
||||||
|
VkPipeline output_pipe;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Renderer-internal represenation of an wlr_buffer imported for rendering.
|
// Renderer-internal represenation of an wlr_buffer imported for rendering.
|
||||||
|
@ -156,6 +157,13 @@ struct wlr_vk_render_buffer {
|
||||||
uint32_t mem_count;
|
uint32_t mem_count;
|
||||||
VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
|
VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
|
||||||
bool transitioned;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_vk_command_buffer {
|
struct wlr_vk_command_buffer {
|
||||||
|
@ -184,11 +192,17 @@ struct wlr_vk_renderer {
|
||||||
VkShaderModule vert_module;
|
VkShaderModule vert_module;
|
||||||
VkShaderModule tex_frag_module;
|
VkShaderModule tex_frag_module;
|
||||||
VkShaderModule quad_frag_module;
|
VkShaderModule quad_frag_module;
|
||||||
|
VkShaderModule output_module;
|
||||||
|
|
||||||
VkDescriptorSetLayout ds_layout, nv12_ds_layout;
|
VkDescriptorSetLayout ds_layout, nv12_ds_layout;
|
||||||
VkPipelineLayout pipe_layout, nv12_pipe_layout;
|
VkPipelineLayout pipe_layout, nv12_pipe_layout;
|
||||||
VkSampler sampler, nv12_sampler;
|
VkSampler sampler, nv12_sampler;
|
||||||
VkSamplerYcbcrConversion nv12_conversion;
|
VkSamplerYcbcrConversion nv12_conversion;
|
||||||
|
// for blend->output subpass
|
||||||
|
VkPipelineLayout output_pipe_layout;
|
||||||
|
VkDescriptorSetLayout output_ds_layout;
|
||||||
|
size_t last_output_pool_size;
|
||||||
|
struct wl_list output_descriptor_pools; // wlr_vk_descriptor_pool.link
|
||||||
|
|
||||||
VkSemaphore timeline_semaphore;
|
VkSemaphore timeline_semaphore;
|
||||||
uint64_t timeline_point;
|
uint64_t timeline_point;
|
||||||
|
@ -208,6 +222,7 @@ struct wlr_vk_renderer {
|
||||||
struct wl_list descriptor_pools; // wlr_vk_descriptor_pool.link
|
struct wl_list descriptor_pools; // wlr_vk_descriptor_pool.link
|
||||||
struct wl_list render_format_setups; // wlr_vk_render_format_setup.link
|
struct wl_list render_format_setups; // wlr_vk_render_format_setup.link
|
||||||
|
|
||||||
|
|
||||||
struct wl_list textures; // wlr_vk_texture.link
|
struct wl_list textures; // wlr_vk_texture.link
|
||||||
// Textures to return to foreign queue
|
// Textures to return to foreign queue
|
||||||
struct wl_list foreign_textures; // wlr_vk_texture.foreign_link
|
struct wl_list foreign_textures; // wlr_vk_texture.foreign_link
|
||||||
|
@ -258,6 +273,12 @@ struct wlr_vk_descriptor_pool *vulkan_alloc_texture_ds(
|
||||||
struct wlr_vk_renderer *renderer, VkDescriptorSetLayout ds_layout,
|
struct wlr_vk_renderer *renderer, VkDescriptorSetLayout ds_layout,
|
||||||
VkDescriptorSet *ds);
|
VkDescriptorSet *ds);
|
||||||
|
|
||||||
|
// Tries to allocate a descriptor set for the blending image. Will
|
||||||
|
// additionally return the pool it was allocated from when successful
|
||||||
|
// (for freeing it later).
|
||||||
|
struct wlr_vk_descriptor_pool *vulkan_alloc_blend_ds(
|
||||||
|
struct wlr_vk_renderer *renderer, VkDescriptorSet *ds);
|
||||||
|
|
||||||
// Frees the given descriptor set from the pool its pool.
|
// Frees the given descriptor set from the pool its pool.
|
||||||
void vulkan_free_ds(struct wlr_vk_renderer *renderer,
|
void vulkan_free_ds(struct wlr_vk_renderer *renderer,
|
||||||
struct wlr_vk_descriptor_pool *pool, VkDescriptorSet ds);
|
struct wlr_vk_descriptor_pool *pool, VkDescriptorSet ds);
|
||||||
|
|
|
@ -293,10 +293,9 @@ static bool query_modifier_support(struct wlr_vk_device *dev,
|
||||||
char render_status[256], texture_status[256];
|
char render_status[256], texture_status[256];
|
||||||
|
|
||||||
// check that specific modifier for render usage
|
// check that specific modifier for render usage
|
||||||
// also, only allow rendering to formats with SRGB encoding
|
|
||||||
const char *errmsg = "unknown error";
|
const char *errmsg = "unknown error";
|
||||||
if ((m.drmFormatModifierTilingFeatures & render_features) == render_features &&
|
if ((m.drmFormatModifierTilingFeatures & render_features) == render_features &&
|
||||||
props->format.is_srgb && !props->format.is_ycbcr) {
|
!props->format.is_ycbcr) {
|
||||||
struct wlr_vk_format_modifier_props p = {0};
|
struct wlr_vk_format_modifier_props p = {0};
|
||||||
if (query_modifier_usage_support(dev, props->format.vk, render_usage, &m, &p, &errmsg)) {
|
if (query_modifier_usage_support(dev, props->format.vk, render_usage, &m, &p, &errmsg)) {
|
||||||
props->dmabuf.render_mods[props->dmabuf.render_mod_count++] = p;
|
props->dmabuf.render_mods[props->dmabuf.render_mod_count++] = p;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "render/vulkan/shaders/common.vert.h"
|
#include "render/vulkan/shaders/common.vert.h"
|
||||||
#include "render/vulkan/shaders/texture.frag.h"
|
#include "render/vulkan/shaders/texture.frag.h"
|
||||||
#include "render/vulkan/shaders/quad.frag.h"
|
#include "render/vulkan/shaders/quad.frag.h"
|
||||||
|
#include "render/vulkan/shaders/output.frag.h"
|
||||||
#include "types/wlr_buffer.h"
|
#include "types/wlr_buffer.h"
|
||||||
#include "types/wlr_matrix.h"
|
#include "types/wlr_matrix.h"
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ 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);
|
struct wlr_vk_renderer *renderer, VkFormat format, bool has_blending_buffer);
|
||||||
|
|
||||||
// vertex shader push constant range data
|
// vertex shader push constant range data
|
||||||
struct vert_pcr_data {
|
struct vert_pcr_data {
|
||||||
|
@ -86,14 +87,15 @@ static void mat3_to_mat4(const float mat3[9], float mat4[4][4]) {
|
||||||
mat4[3][3] = 1.f;
|
mat4[3][3] = 1.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_vk_descriptor_pool *vulkan_alloc_texture_ds(
|
static struct wlr_vk_descriptor_pool *alloc_ds(
|
||||||
struct wlr_vk_renderer *renderer, VkDescriptorSetLayout ds_layout,
|
struct wlr_vk_renderer *renderer, VkDescriptorSet *ds,
|
||||||
VkDescriptorSet *ds) {
|
VkDescriptorType type, const VkDescriptorSetLayout *layout,
|
||||||
|
struct wl_list *pool_list, size_t *last_pool_size) {
|
||||||
VkResult res;
|
VkResult res;
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
struct wlr_vk_descriptor_pool *pool;
|
struct wlr_vk_descriptor_pool *pool;
|
||||||
wl_list_for_each(pool, &renderer->descriptor_pools, link) {
|
wl_list_for_each(pool, pool_list, link) {
|
||||||
if (pool->free > 0) {
|
if (pool->free > 0) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
@ -107,7 +109,7 @@ struct wlr_vk_descriptor_pool *vulkan_alloc_texture_ds(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t count = 2 * renderer->last_pool_size;
|
size_t count = 2 * (*last_pool_size);
|
||||||
if (!count) {
|
if (!count) {
|
||||||
count = start_descriptor_pool_size;
|
count = start_descriptor_pool_size;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +117,7 @@ struct wlr_vk_descriptor_pool *vulkan_alloc_texture_ds(
|
||||||
pool->free = count;
|
pool->free = count;
|
||||||
VkDescriptorPoolSize pool_size = {
|
VkDescriptorPoolSize pool_size = {
|
||||||
.descriptorCount = count,
|
.descriptorCount = count,
|
||||||
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
.type = type,
|
||||||
};
|
};
|
||||||
|
|
||||||
VkDescriptorPoolCreateInfo dpool_info = {
|
VkDescriptorPoolCreateInfo dpool_info = {
|
||||||
|
@ -134,14 +136,14 @@ struct wlr_vk_descriptor_pool *vulkan_alloc_texture_ds(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer->last_pool_size = count;
|
*last_pool_size = count;
|
||||||
wl_list_insert(&renderer->descriptor_pools, &pool->link);
|
wl_list_insert(pool_list, &pool->link);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSetAllocateInfo ds_info = {
|
VkDescriptorSetAllocateInfo ds_info = {
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||||
.descriptorSetCount = 1,
|
.descriptorSetCount = 1,
|
||||||
.pSetLayouts = &ds_layout,
|
.pSetLayouts = layout,
|
||||||
.descriptorPool = pool->pool,
|
.descriptorPool = pool->pool,
|
||||||
};
|
};
|
||||||
res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
|
res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
|
||||||
|
@ -154,6 +156,21 @@ struct wlr_vk_descriptor_pool *vulkan_alloc_texture_ds(
|
||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wlr_vk_descriptor_pool *vulkan_alloc_texture_ds(
|
||||||
|
struct wlr_vk_renderer *renderer, VkDescriptorSetLayout ds_layout,
|
||||||
|
VkDescriptorSet *ds) {
|
||||||
|
return alloc_ds(renderer, ds, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
|
&ds_layout, &renderer->descriptor_pools,
|
||||||
|
&renderer->last_pool_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_vk_descriptor_pool *vulkan_alloc_blend_ds(
|
||||||
|
struct wlr_vk_renderer *renderer, VkDescriptorSet *ds) {
|
||||||
|
return alloc_ds(renderer, ds, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
||||||
|
&renderer->output_ds_layout, &renderer->output_descriptor_pools,
|
||||||
|
&renderer->last_output_pool_size);
|
||||||
|
}
|
||||||
|
|
||||||
void vulkan_free_ds(struct wlr_vk_renderer *renderer,
|
void vulkan_free_ds(struct wlr_vk_renderer *renderer,
|
||||||
struct wlr_vk_descriptor_pool *pool, VkDescriptorSet ds) {
|
struct wlr_vk_descriptor_pool *pool, VkDescriptorSet ds) {
|
||||||
vkFreeDescriptorSets(renderer->dev->dev, pool->pool, 1, &ds);
|
vkFreeDescriptorSets(renderer->dev->dev, pool->pool, 1, &ds);
|
||||||
|
@ -171,6 +188,7 @@ static void destroy_render_format_setup(struct wlr_vk_renderer *renderer,
|
||||||
vkDestroyPipeline(dev, setup->tex_identity_pipe, NULL);
|
vkDestroyPipeline(dev, setup->tex_identity_pipe, NULL);
|
||||||
vkDestroyPipeline(dev, setup->tex_srgb_pipe, NULL);
|
vkDestroyPipeline(dev, setup->tex_srgb_pipe, NULL);
|
||||||
vkDestroyPipeline(dev, setup->tex_nv12_pipe, NULL);
|
vkDestroyPipeline(dev, setup->tex_nv12_pipe, NULL);
|
||||||
|
vkDestroyPipeline(dev, setup->output_pipe, NULL);
|
||||||
vkDestroyPipeline(dev, setup->quad_pipe, NULL);
|
vkDestroyPipeline(dev, setup->quad_pipe, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,6 +602,14 @@ static void destroy_render_buffer(struct wlr_vk_render_buffer *buffer) {
|
||||||
vkFreeMemory(dev, buffer->memories[i], NULL);
|
vkFreeMemory(dev, buffer->memories[i], NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,9 +623,119 @@ static struct wlr_addon_interface render_buffer_addon_impl = {
|
||||||
.destroy = handle_render_buffer_destroy,
|
.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) {
|
||||||
|
VkResult res;
|
||||||
|
VkDevice dev = renderer->dev->dev;
|
||||||
|
|
||||||
|
// Set up an extra 16F buffer on which to do linear blending,
|
||||||
|
// and afterwards to render onto the target
|
||||||
|
VkImageCreateInfo img_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||||
|
.imageType = VK_IMAGE_TYPE_2D,
|
||||||
|
.format = VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||||
|
.mipLevels = 1,
|
||||||
|
.arrayLayers = 1,
|
||||||
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||||
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||||
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||||
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
.extent = (VkExtent3D) { width, height, 1 },
|
||||||
|
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
res = vkCreateImage(dev, &img_info, NULL, &buffer->blend_image);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("vkCreateImage failed", res);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkMemoryRequirements mem_reqs;
|
||||||
|
vkGetImageMemoryRequirements(dev, buffer->blend_image, &mem_reqs);
|
||||||
|
|
||||||
|
int mem_type_index = vulkan_find_mem_type(renderer->dev,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, mem_reqs.memoryTypeBits);
|
||||||
|
if (mem_type_index == -1) {
|
||||||
|
wlr_log(WLR_ERROR, "failed to find suitable vulkan memory type");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo mem_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||||
|
.allocationSize = mem_reqs.size,
|
||||||
|
.memoryTypeIndex = mem_type_index,
|
||||||
|
};
|
||||||
|
|
||||||
|
res = vkAllocateMemory(dev, &mem_info, NULL, &buffer->blend_memory);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("vkAllocatorMemory failed", res);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = vkBindImageMemory(dev, buffer->blend_image, buffer->blend_memory, 0);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("vkBindMemory failed", res);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageViewCreateInfo blend_view_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||||
|
.image = buffer->blend_image,
|
||||||
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||||
|
.format = img_info.format,
|
||||||
|
.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, &blend_view_info, NULL, &buffer->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) {
|
||||||
|
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,
|
||||||
|
.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,
|
||||||
|
.dstBinding = 0,
|
||||||
|
.pImageInfo = &ds_attach_info,
|
||||||
|
};
|
||||||
|
vkUpdateDescriptorSets(dev, 1, &ds_write, 0, NULL);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
// cleaning up blend_attachment_pool, blend_descriptor_set, blend_image,
|
||||||
|
// blend_memory, and blend_image_view 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(
|
static struct wlr_vk_render_buffer *create_render_buffer(
|
||||||
struct wlr_vk_renderer *renderer, struct wlr_buffer *wlr_buffer) {
|
struct wlr_vk_renderer *renderer, struct wlr_buffer *wlr_buffer) {
|
||||||
VkResult res;
|
VkResult res;
|
||||||
|
VkDevice dev = renderer->dev->dev;
|
||||||
|
|
||||||
struct wlr_vk_render_buffer *buffer = calloc(1, sizeof(*buffer));
|
struct wlr_vk_render_buffer *buffer = calloc(1, sizeof(*buffer));
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
|
@ -611,7 +747,7 @@ static struct wlr_vk_render_buffer *create_render_buffer(
|
||||||
|
|
||||||
struct wlr_dmabuf_attributes dmabuf = {0};
|
struct wlr_dmabuf_attributes dmabuf = {0};
|
||||||
if (!wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) {
|
if (!wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) {
|
||||||
goto error_buffer;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_log(WLR_DEBUG, "vulkan create_render_buffer: %.4s, %dx%d",
|
wlr_log(WLR_DEBUG, "vulkan create_render_buffer: %.4s, %dx%d",
|
||||||
|
@ -620,16 +756,15 @@ static struct wlr_vk_render_buffer *create_render_buffer(
|
||||||
buffer->image = vulkan_import_dmabuf(renderer, &dmabuf,
|
buffer->image = vulkan_import_dmabuf(renderer, &dmabuf,
|
||||||
buffer->memories, &buffer->mem_count, true);
|
buffer->memories, &buffer->mem_count, true);
|
||||||
if (!buffer->image) {
|
if (!buffer->image) {
|
||||||
goto error_buffer;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDevice dev = renderer->dev->dev;
|
|
||||||
const struct wlr_vk_format_props *fmt = vulkan_format_props_from_drm(
|
const struct wlr_vk_format_props *fmt = vulkan_format_props_from_drm(
|
||||||
renderer->dev, dmabuf.format);
|
renderer->dev, dmabuf.format);
|
||||||
if (fmt == NULL) {
|
if (fmt == NULL) {
|
||||||
wlr_log(WLR_ERROR, "Unsupported pixel format %"PRIx32 " (%.4s)",
|
wlr_log(WLR_ERROR, "Unsupported pixel format %"PRIx32 " (%.4s)",
|
||||||
dmabuf.format, (const char*) &dmabuf.format);
|
dmabuf.format, (const char*) &dmabuf.format);
|
||||||
goto error_buffer;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageViewCreateInfo view_info = {
|
VkImageViewCreateInfo view_info = {
|
||||||
|
@ -653,18 +788,32 @@ 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->image_view);
|
||||||
if (res != VK_SUCCESS) {
|
if (res != VK_SUCCESS) {
|
||||||
wlr_vk_error("vkCreateImageView failed", res);
|
wlr_vk_error("vkCreateImageView failed", res);
|
||||||
goto error_view;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->render_setup = find_or_create_render_setup(renderer, fmt->format.vk);
|
bool has_blending_buffer = !fmt->format.is_srgb;
|
||||||
|
|
||||||
|
buffer->render_setup = find_or_create_render_setup(
|
||||||
|
renderer, fmt->format.vk, has_blending_buffer);
|
||||||
if (!buffer->render_setup) {
|
if (!buffer->render_setup) {
|
||||||
goto error_view;
|
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 = {
|
VkFramebufferCreateInfo fb_info = {
|
||||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||||
.attachmentCount = 1u,
|
.attachmentCount = attachment_count,
|
||||||
.pAttachments = &buffer->image_view,
|
.pAttachments = attachments,
|
||||||
.flags = 0u,
|
.flags = 0u,
|
||||||
.width = dmabuf.width,
|
.width = dmabuf.width,
|
||||||
.height = dmabuf.height,
|
.height = dmabuf.height,
|
||||||
|
@ -675,23 +824,32 @@ static struct wlr_vk_render_buffer *create_render_buffer(
|
||||||
res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->framebuffer);
|
res = vkCreateFramebuffer(dev, &fb_info, NULL, &buffer->framebuffer);
|
||||||
if (res != VK_SUCCESS) {
|
if (res != VK_SUCCESS) {
|
||||||
wlr_vk_error("vkCreateFramebuffer", res);
|
wlr_vk_error("vkCreateFramebuffer", res);
|
||||||
goto error_view;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
wlr_addon_init(&buffer->addon, &wlr_buffer->addons, renderer,
|
wlr_addon_init(&buffer->addon, &wlr_buffer->addons, renderer,
|
||||||
&render_buffer_addon_impl);
|
&render_buffer_addon_impl);
|
||||||
wl_list_insert(&renderer->render_buffers, &buffer->link);
|
wl_list_insert(&renderer->render_buffers, &buffer->link);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
|
|
||||||
error_view:
|
error:
|
||||||
|
if (buffer->blend_attachment_pool) {
|
||||||
|
vulkan_free_ds(buffer->renderer, buffer->blend_attachment_pool,
|
||||||
|
buffer->blend_descriptor_set);
|
||||||
|
}
|
||||||
|
vkDestroyImage(dev, buffer->blend_image, NULL);
|
||||||
|
vkFreeMemory(dev, buffer->blend_memory, NULL);
|
||||||
|
vkDestroyImageView(dev, buffer->blend_image_view, NULL);
|
||||||
|
|
||||||
vkDestroyFramebuffer(dev, buffer->framebuffer, NULL);
|
vkDestroyFramebuffer(dev, buffer->framebuffer, NULL);
|
||||||
vkDestroyImageView(dev, buffer->image_view, NULL);
|
vkDestroyImageView(dev, buffer->image_view, NULL);
|
||||||
vkDestroyImage(dev, buffer->image, NULL);
|
vkDestroyImage(dev, buffer->image, NULL);
|
||||||
for (size_t i = 0u; i < buffer->mem_count; ++i) {
|
for (size_t i = 0u; i < buffer->mem_count; ++i) {
|
||||||
vkFreeMemory(dev, buffer->memories[i], NULL);
|
vkFreeMemory(dev, buffer->memories[i], NULL);
|
||||||
}
|
}
|
||||||
error_buffer:
|
|
||||||
wlr_dmabuf_attributes_finish(&dmabuf);
|
wlr_dmabuf_attributes_finish(&dmabuf);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -919,12 +1077,45 @@ static void vulkan_end(struct wlr_renderer *wlr_renderer) {
|
||||||
assert(stage_cb != NULL);
|
assert(stage_cb != NULL);
|
||||||
renderer->stage.cb = NULL;
|
renderer->stage.cb = NULL;
|
||||||
|
|
||||||
|
struct wlr_vk_render_buffer *current_rb = renderer->current_render_buffer;
|
||||||
|
|
||||||
|
if (current_rb->blend_image) {
|
||||||
|
// Apply output shader to map blend image to actual output image
|
||||||
|
vkCmdNextSubpass(render_cb->vk, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
|
VkPipeline pipe = current_rb->render_setup->output_pipe;
|
||||||
|
if (pipe != renderer->bound_pipe) {
|
||||||
|
vkCmdBindPipeline(render_cb->vk, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
|
||||||
|
renderer->bound_pipe = pipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
float final_matrix[9] = {
|
||||||
|
renderer->render_width, 0.f, -1.f,
|
||||||
|
0.f, renderer->render_height, -1.f,
|
||||||
|
0.f, 0.f, 0.f,
|
||||||
|
};
|
||||||
|
struct vert_pcr_data vert_pcr_data;
|
||||||
|
mat3_to_mat4(final_matrix, vert_pcr_data.mat4);
|
||||||
|
vert_pcr_data.uv_off[0] = 0.f;
|
||||||
|
vert_pcr_data.uv_off[1] = 0.f;
|
||||||
|
vert_pcr_data.uv_size[0] = 1.f;
|
||||||
|
vert_pcr_data.uv_size[1] = 1.f;
|
||||||
|
|
||||||
|
vkCmdPushConstants(render_cb->vk, renderer->output_pipe_layout,
|
||||||
|
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data);
|
||||||
|
vkCmdBindDescriptorSets(render_cb->vk,
|
||||||
|
VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->output_pipe_layout,
|
||||||
|
0, 1, ¤t_rb->blend_descriptor_set, 0, NULL);
|
||||||
|
|
||||||
|
vkCmdDraw(render_cb->vk, 4, 1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCmdEndRenderPass(render_cb->vk);
|
||||||
|
|
||||||
renderer->render_width = 0u;
|
renderer->render_width = 0u;
|
||||||
renderer->render_height = 0u;
|
renderer->render_height = 0u;
|
||||||
renderer->bound_pipe = VK_NULL_HANDLE;
|
renderer->bound_pipe = VK_NULL_HANDLE;
|
||||||
|
|
||||||
vkCmdEndRenderPass(render_cb->vk);
|
|
||||||
|
|
||||||
// insert acquire and release barriers for dmabuf-images
|
// insert acquire and release barriers for dmabuf-images
|
||||||
unsigned barrier_count = wl_list_length(&renderer->foreign_textures) + 1;
|
unsigned barrier_count = wl_list_length(&renderer->foreign_textures) + 1;
|
||||||
VkImageMemoryBarrier *acquire_barriers = calloc(barrier_count, sizeof(VkImageMemoryBarrier));
|
VkImageMemoryBarrier *acquire_barriers = calloc(barrier_count, sizeof(VkImageMemoryBarrier));
|
||||||
|
@ -1001,9 +1192,9 @@ static void vulkan_end(struct wlr_renderer *wlr_renderer) {
|
||||||
|
|
||||||
// also add acquire/release barriers for the current render buffer
|
// also add acquire/release barriers for the current render buffer
|
||||||
VkImageLayout src_layout = VK_IMAGE_LAYOUT_GENERAL;
|
VkImageLayout src_layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
if (!renderer->current_render_buffer->transitioned) {
|
if (!current_rb->transitioned) {
|
||||||
src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||||
renderer->current_render_buffer->transitioned = true;
|
current_rb->transitioned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// acquire render buffer before rendering
|
// acquire render buffer before rendering
|
||||||
|
@ -1040,6 +1231,36 @@ static void vulkan_end(struct wlr_renderer *wlr_renderer) {
|
||||||
|
|
||||||
++idx;
|
++idx;
|
||||||
|
|
||||||
|
if (current_rb->blend_image) {
|
||||||
|
// 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 (!current_rb->blend_transitioned) {
|
||||||
|
blend_src_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
current_rb->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 = current_rb->blend_image,
|
||||||
|
.oldLayout = blend_src_layout,
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||||
|
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||||
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
|
.subresourceRange = {
|
||||||
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
.layerCount = 1,
|
||||||
|
.levelCount = 1,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
vkCmdPipelineBarrier(stage_cb->vk, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
0, 0, NULL, 0, NULL, 1, &blend_acq_barrier);
|
||||||
|
}
|
||||||
|
|
||||||
vkCmdPipelineBarrier(stage_cb->vk, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
vkCmdPipelineBarrier(stage_cb->vk, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
0, 0, NULL, 0, NULL, barrier_count, acquire_barriers);
|
0, 0, NULL, 0, NULL, barrier_count, acquire_barriers);
|
||||||
|
@ -1407,14 +1628,21 @@ static void vulkan_destroy(struct wlr_renderer *wlr_renderer) {
|
||||||
vkDestroyDescriptorPool(dev->dev, pool->pool, NULL);
|
vkDestroyDescriptorPool(dev->dev, pool->pool, NULL);
|
||||||
free(pool);
|
free(pool);
|
||||||
}
|
}
|
||||||
|
wl_list_for_each_safe(pool, tmp_pool, &renderer->output_descriptor_pools, link) {
|
||||||
|
vkDestroyDescriptorPool(dev->dev, pool->pool, NULL);
|
||||||
|
free(pool);
|
||||||
|
}
|
||||||
|
|
||||||
vkDestroyShaderModule(dev->dev, renderer->vert_module, NULL);
|
vkDestroyShaderModule(dev->dev, renderer->vert_module, NULL);
|
||||||
vkDestroyShaderModule(dev->dev, renderer->tex_frag_module, NULL);
|
vkDestroyShaderModule(dev->dev, renderer->tex_frag_module, NULL);
|
||||||
vkDestroyShaderModule(dev->dev, renderer->quad_frag_module, NULL);
|
vkDestroyShaderModule(dev->dev, renderer->quad_frag_module, NULL);
|
||||||
|
vkDestroyShaderModule(dev->dev, renderer->output_module, NULL);
|
||||||
|
|
||||||
vkDestroySemaphore(dev->dev, renderer->timeline_semaphore, NULL);
|
vkDestroySemaphore(dev->dev, renderer->timeline_semaphore, NULL);
|
||||||
vkDestroyPipelineLayout(dev->dev, renderer->pipe_layout, NULL);
|
vkDestroyPipelineLayout(dev->dev, renderer->pipe_layout, NULL);
|
||||||
vkDestroyDescriptorSetLayout(dev->dev, renderer->ds_layout, NULL);
|
vkDestroyDescriptorSetLayout(dev->dev, renderer->ds_layout, NULL);
|
||||||
|
vkDestroyPipelineLayout(dev->dev, renderer->output_pipe_layout, NULL);
|
||||||
|
vkDestroyDescriptorSetLayout(dev->dev, renderer->output_ds_layout, NULL);
|
||||||
vkDestroySampler(dev->dev, renderer->sampler, NULL);
|
vkDestroySampler(dev->dev, renderer->sampler, NULL);
|
||||||
vkDestroySamplerYcbcrConversion(dev->dev, renderer->nv12_conversion, NULL);
|
vkDestroySamplerYcbcrConversion(dev->dev, renderer->nv12_conversion, NULL);
|
||||||
vkDestroyCommandPool(dev->dev, renderer->command_pool, NULL);
|
vkDestroyCommandPool(dev->dev, renderer->command_pool, NULL);
|
||||||
|
@ -1786,6 +2014,58 @@ static bool init_tex_layouts(struct wlr_vk_renderer *renderer,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer,
|
||||||
|
VkDescriptorSetLayout *out_ds_layout,
|
||||||
|
VkPipelineLayout *out_pipe_layout) {
|
||||||
|
VkResult res;
|
||||||
|
VkDevice dev = renderer->dev->dev;
|
||||||
|
|
||||||
|
// layouts, descriptor set
|
||||||
|
VkDescriptorSetLayoutBinding ds_binding = {
|
||||||
|
.binding = 0,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
|
.pImmutableSamplers = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo ds_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||||
|
.bindingCount = 1,
|
||||||
|
.pBindings = &ds_binding,
|
||||||
|
};
|
||||||
|
|
||||||
|
res = vkCreateDescriptorSetLayout(dev, &ds_info, NULL, out_ds_layout);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("vkCreateDescriptorSetLayout", res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pipeline layout -- standard vertex uniforms, no shader uniforms
|
||||||
|
VkPushConstantRange pc_ranges[1] = {
|
||||||
|
{
|
||||||
|
.size = sizeof(struct vert_pcr_data),
|
||||||
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo pl_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||||
|
.setLayoutCount = 1,
|
||||||
|
.pSetLayouts = out_ds_layout,
|
||||||
|
.pushConstantRangeCount = 1,
|
||||||
|
.pPushConstantRanges = pc_ranges,
|
||||||
|
};
|
||||||
|
|
||||||
|
res = vkCreatePipelineLayout(dev, &pl_info, NULL, out_pipe_layout);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("vkCreatePipelineLayout", res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Initializes the pipeline for rendering textures and using the given
|
// Initializes the pipeline for rendering textures and using the given
|
||||||
// VkRenderPass and VkPipelineLayout.
|
// VkRenderPass and VkPipelineLayout.
|
||||||
static bool init_tex_pipeline(struct wlr_vk_renderer *renderer,
|
static bool init_tex_pipeline(struct wlr_vk_renderer *renderer,
|
||||||
|
@ -1916,6 +2196,110 @@ static bool init_tex_pipeline(struct wlr_vk_renderer *renderer,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer,
|
||||||
|
VkRenderPass rp, VkPipelineLayout pipe_layout, VkPipeline *pipe) {
|
||||||
|
VkResult res;
|
||||||
|
VkDevice dev = renderer->dev->dev;
|
||||||
|
|
||||||
|
// shaders
|
||||||
|
VkPipelineShaderStageCreateInfo tex_stages[2] = {
|
||||||
|
{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||||
|
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
.module = renderer->vert_module,
|
||||||
|
.pName = "main",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||||
|
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
|
.module = renderer->output_module,
|
||||||
|
.pName = "main",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// info
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo assembly = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||||
|
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineRasterizationStateCreateInfo rasterization = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||||
|
.polygonMode = VK_POLYGON_MODE_FILL,
|
||||||
|
.cullMode = VK_CULL_MODE_NONE,
|
||||||
|
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
|
||||||
|
.lineWidth = 1.f,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineColorBlendAttachmentState blend_attachment = {
|
||||||
|
.blendEnable = false,
|
||||||
|
.colorWriteMask =
|
||||||
|
VK_COLOR_COMPONENT_R_BIT |
|
||||||
|
VK_COLOR_COMPONENT_G_BIT |
|
||||||
|
VK_COLOR_COMPONENT_B_BIT |
|
||||||
|
VK_COLOR_COMPONENT_A_BIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineColorBlendStateCreateInfo blend = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||||
|
.attachmentCount = 1,
|
||||||
|
.pAttachments = &blend_attachment,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineMultisampleStateCreateInfo multisample = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
|
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineViewportStateCreateInfo viewport = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||||
|
.viewportCount = 1,
|
||||||
|
.scissorCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkDynamicState dynStates[2] = {
|
||||||
|
VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
|
VK_DYNAMIC_STATE_SCISSOR,
|
||||||
|
};
|
||||||
|
VkPipelineDynamicStateCreateInfo dynamic = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||||
|
.pDynamicStates = dynStates,
|
||||||
|
.dynamicStateCount = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineVertexInputStateCreateInfo vertex = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkGraphicsPipelineCreateInfo pinfo = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
|
.pNext = NULL,
|
||||||
|
.layout = pipe_layout,
|
||||||
|
.renderPass = rp,
|
||||||
|
.subpass = 1, // second subpass!
|
||||||
|
.stageCount = 2,
|
||||||
|
.pStages = tex_stages,
|
||||||
|
.pInputAssemblyState = &assembly,
|
||||||
|
.pRasterizationState = &rasterization,
|
||||||
|
.pColorBlendState = &blend,
|
||||||
|
.pMultisampleState = &multisample,
|
||||||
|
.pViewportState = &viewport,
|
||||||
|
.pDynamicState = &dynamic,
|
||||||
|
.pVertexInputState = &vertex,
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE: use could use a cache here for faster loading
|
||||||
|
// store it somewhere like $XDG_CACHE_HOME/wlroots/vk_pipe_cache
|
||||||
|
VkPipelineCache cache = VK_NULL_HANDLE;
|
||||||
|
res = vkCreateGraphicsPipelines(dev, cache, 1, &pinfo, NULL, pipe);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("failed to create vulkan pipelines:", res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Creates static render data, such as sampler, layouts and shader modules
|
// Creates static render data, such as sampler, layouts and shader modules
|
||||||
// for the given rednerer.
|
// for the given rednerer.
|
||||||
// Cleanup is done by destroying the renderer.
|
// Cleanup is done by destroying the renderer.
|
||||||
|
@ -1957,6 +2341,11 @@ static bool init_static_render_data(struct wlr_vk_renderer *renderer) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!init_blend_to_output_layouts(renderer, &renderer->output_ds_layout,
|
||||||
|
&renderer->output_pipe_layout)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// load vert module and tex frag module since they are needed to
|
// load vert module and tex frag module since they are needed to
|
||||||
// initialize the tex pipeline
|
// initialize the tex pipeline
|
||||||
VkShaderModuleCreateInfo sinfo = {
|
VkShaderModuleCreateInfo sinfo = {
|
||||||
|
@ -1994,11 +2383,23 @@ static bool init_static_render_data(struct wlr_vk_renderer *renderer) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// quad frag
|
||||||
|
sinfo = (VkShaderModuleCreateInfo){
|
||||||
|
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||||
|
.codeSize = sizeof(output_frag_data),
|
||||||
|
.pCode = output_frag_data,
|
||||||
|
};
|
||||||
|
res = vkCreateShaderModule(dev, &sinfo, NULL, &renderer->output_module);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("Failed to create blend->output fragment shader module", res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
struct wlr_vk_renderer *renderer, VkFormat 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) {
|
||||||
|
@ -2018,72 +2419,189 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup(
|
||||||
VkDevice dev = renderer->dev->dev;
|
VkDevice dev = renderer->dev->dev;
|
||||||
VkResult res;
|
VkResult res;
|
||||||
|
|
||||||
VkAttachmentDescription attachment = {
|
if (has_blending_buffer) {
|
||||||
.format = format,
|
VkAttachmentDescription attachments[2] = {
|
||||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
{
|
||||||
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
|
.format = VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||||
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||||
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||||
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||||
};
|
.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||||
|
.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.format = format,
|
||||||
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||||
|
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||||
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||||
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||||
|
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
VkAttachmentReference color_ref = {
|
VkAttachmentReference blend_write_ref = {
|
||||||
.attachment = 0u,
|
.attachment = 0u,
|
||||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
VkSubpassDescription subpass = {
|
VkAttachmentReference blend_read_ref = {
|
||||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
.attachment = 0u,
|
||||||
.colorAttachmentCount = 1,
|
.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
.pColorAttachments = &color_ref,
|
};
|
||||||
};
|
|
||||||
|
|
||||||
VkSubpassDependency deps[2] = {
|
VkAttachmentReference color_ref = {
|
||||||
{
|
.attachment = 1u,
|
||||||
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||||
.srcStageMask = VK_PIPELINE_STAGE_HOST_BIT |
|
};
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT |
|
|
||||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT |
|
|
||||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
||||||
.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT |
|
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT |
|
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
||||||
.dstSubpass = 0,
|
|
||||||
.dstStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
|
|
||||||
.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT |
|
|
||||||
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
|
|
||||||
VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
|
|
||||||
VK_ACCESS_SHADER_READ_BIT,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.srcSubpass = 0,
|
|
||||||
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
||||||
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
||||||
.dstSubpass = VK_SUBPASS_EXTERNAL,
|
|
||||||
.dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT |
|
|
||||||
VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
|
||||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT |
|
|
||||||
VK_ACCESS_MEMORY_READ_BIT,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
VkRenderPassCreateInfo rp_info = {
|
VkSubpassDescription subpasses[2] = {
|
||||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
{
|
||||||
.attachmentCount = 1,
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
.pAttachments = &attachment,
|
.colorAttachmentCount = 1,
|
||||||
.subpassCount = 1,
|
.pColorAttachments = &blend_write_ref,
|
||||||
.pSubpasses = &subpass,
|
},
|
||||||
.dependencyCount = 2u,
|
{
|
||||||
.pDependencies = deps,
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
};
|
.inputAttachmentCount = 1,
|
||||||
|
.pInputAttachments = &blend_read_ref,
|
||||||
|
.colorAttachmentCount = 1,
|
||||||
|
.pColorAttachments = &color_ref,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
res = vkCreateRenderPass(dev, &rp_info, NULL, &setup->render_pass);
|
VkSubpassDependency deps[3] = {
|
||||||
if (res != VK_SUCCESS) {
|
{
|
||||||
wlr_vk_error("Failed to create render pass", res);
|
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
||||||
free(setup);
|
.srcStageMask = VK_PIPELINE_STAGE_HOST_BIT |
|
||||||
return NULL;
|
VK_PIPELINE_STAGE_TRANSFER_BIT |
|
||||||
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT |
|
||||||
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT |
|
||||||
|
VK_ACCESS_TRANSFER_WRITE_BIT |
|
||||||
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
|
.dstSubpass = 0,
|
||||||
|
.dstStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
|
||||||
|
.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT |
|
||||||
|
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
|
||||||
|
VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
|
||||||
|
VK_ACCESS_SHADER_READ_BIT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.srcSubpass = 0,
|
||||||
|
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
|
.dstSubpass = 1,
|
||||||
|
.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
|
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||||
|
.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.srcSubpass = 1,
|
||||||
|
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
|
.dstSubpass = VK_SUBPASS_EXTERNAL,
|
||||||
|
.dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT |
|
||||||
|
VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
|
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT |
|
||||||
|
VK_ACCESS_MEMORY_READ_BIT,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
VkRenderPassCreateInfo rp_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||||
|
.pNext = NULL,
|
||||||
|
.flags = 0,
|
||||||
|
.attachmentCount = 2u,
|
||||||
|
.pAttachments = attachments,
|
||||||
|
.subpassCount = 2u,
|
||||||
|
.pSubpasses = subpasses,
|
||||||
|
.dependencyCount = 3u,
|
||||||
|
.pDependencies = deps,
|
||||||
|
};
|
||||||
|
|
||||||
|
res = vkCreateRenderPass(dev, &rp_info, NULL, &setup->render_pass);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("Failed to create 2-step render pass", res);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is only well defined if render pass has a 2nd subpass
|
||||||
|
if (!init_blend_to_output_pipeline(
|
||||||
|
renderer, setup->render_pass, renderer->output_pipe_layout,
|
||||||
|
&setup->output_pipe)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VkAttachmentDescription attachment = {
|
||||||
|
.format = format,
|
||||||
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||||
|
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||||
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||||
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||||
|
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkAttachmentReference color_ref = {
|
||||||
|
.attachment = 0u,
|
||||||
|
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkSubpassDescription subpass = {
|
||||||
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
.colorAttachmentCount = 1,
|
||||||
|
.pColorAttachments = &color_ref,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkSubpassDependency deps[2] = {
|
||||||
|
{
|
||||||
|
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
||||||
|
.srcStageMask = VK_PIPELINE_STAGE_HOST_BIT |
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT |
|
||||||
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT |
|
||||||
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT |
|
||||||
|
VK_ACCESS_TRANSFER_WRITE_BIT |
|
||||||
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
|
.dstSubpass = 0,
|
||||||
|
.dstStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
|
||||||
|
.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT |
|
||||||
|
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
|
||||||
|
VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
|
||||||
|
VK_ACCESS_SHADER_READ_BIT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.srcSubpass = 0,
|
||||||
|
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
|
.dstSubpass = VK_SUBPASS_EXTERNAL,
|
||||||
|
.dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT |
|
||||||
|
VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
|
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT |
|
||||||
|
VK_ACCESS_MEMORY_READ_BIT,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
VkRenderPassCreateInfo rp_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||||
|
.attachmentCount = 1,
|
||||||
|
.pAttachments = &attachment,
|
||||||
|
.subpassCount = 1,
|
||||||
|
.pSubpasses = &subpass,
|
||||||
|
.dependencyCount = 2u,
|
||||||
|
.pDependencies = deps,
|
||||||
|
};
|
||||||
|
|
||||||
|
res = vkCreateRenderPass(dev, &rp_info, NULL, &setup->render_pass);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("Failed to create render pass", res);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!init_tex_pipeline(renderer, setup->render_pass, renderer->pipe_layout,
|
if (!init_tex_pipeline(renderer, setup->render_pass, renderer->pipe_layout,
|
||||||
|
@ -2225,6 +2743,7 @@ struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev
|
||||||
wl_list_init(&renderer->foreign_textures);
|
wl_list_init(&renderer->foreign_textures);
|
||||||
wl_list_init(&renderer->textures);
|
wl_list_init(&renderer->textures);
|
||||||
wl_list_init(&renderer->descriptor_pools);
|
wl_list_init(&renderer->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);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ vulkan_shaders_src = [
|
||||||
'common.vert',
|
'common.vert',
|
||||||
'texture.frag',
|
'texture.frag',
|
||||||
'quad.frag',
|
'quad.frag',
|
||||||
|
'output.frag',
|
||||||
]
|
]
|
||||||
|
|
||||||
vulkan_shaders = []
|
vulkan_shaders = []
|
||||||
|
|
21
render/vulkan/shaders/output.frag
Normal file
21
render/vulkan/shaders/output.frag
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout (input_attachment_index = 0, binding = 0) uniform subpassInput in_color;
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 uv;
|
||||||
|
layout(location = 0) out vec4 out_color;
|
||||||
|
|
||||||
|
float linear_to_srgb(float x) {
|
||||||
|
return max(min(x * 12.92, 0.04045), 1.055 * pow(x, 1. / 2.4) - 0.055);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 val = subpassLoad(in_color).rgba;
|
||||||
|
out_color = vec4(
|
||||||
|
linear_to_srgb(val.r),
|
||||||
|
linear_to_srgb(val.g),
|
||||||
|
linear_to_srgb(val.b),
|
||||||
|
val.a
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue