mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-21 11:30:18 +00:00
24d096597b
Includes a new GstVulkanHandlePool base class for pooling different resources togther. The descriptor cache object is ported to GstVulkanHandlePool with the exact same functionality. A new GstVulkanFenceCache is also implemented for caching fences which is used internally by GstVulkanDevice for creating or reusing fences. The existing GstVulkanTrashFenceList object now caches trash objects.
1337 lines
42 KiB
C
1337 lines
42 KiB
C
/*
|
|
* GStreamer Plugins Vulkan
|
|
* Copyright (C) 2019 Matthew Waters <matthew@centricular.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "vkfullscreenquad.h"
|
|
#include "vkelementutils.h"
|
|
|
|
#define GST_CAT_DEFAULT gst_vulkan_full_screen_quad_debug
|
|
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
|
|
|
typedef struct _GstVulkanFullScreenQuad GstVulkanFullScreenQuad;
|
|
|
|
struct _GstVulkanFullScreenQuadPrivate
|
|
{
|
|
GstBuffer *inbuf;
|
|
GstBuffer *outbuf;
|
|
|
|
GstMemory *vertices;
|
|
GstMemory *indices;
|
|
gsize n_indices;
|
|
GstMemory *uniforms;
|
|
gsize uniform_size;
|
|
|
|
GstMemory *push_constants;
|
|
gsize push_constants_size;
|
|
|
|
GstVulkanHandle *vert;
|
|
GstVulkanHandle *frag;
|
|
};
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (GstVulkanFullScreenQuad, gst_vulkan_full_screen_quad,
|
|
GST_TYPE_OBJECT, GST_DEBUG_CATEGORY_INIT (gst_vulkan_full_screen_quad_debug,
|
|
"vulkanfullscreenquad", 0, "vulkan fullscreen quad render");
|
|
G_ADD_PRIVATE (GstVulkanFullScreenQuad));
|
|
|
|
#define GET_PRIV(self) gst_vulkan_full_screen_quad_get_instance_private (self)
|
|
|
|
struct Vertex vertices[] = {
|
|
{-1.0f, -1.0f, 0.0f, 0.0f, 0.0f},
|
|
{1.0f, -1.0f, 0.0f, 1.0f, 0.0f},
|
|
{1.0f, 1.0f, 0.0f, 1.0f, 1.0f},
|
|
{-1.0f, 1.0f, 0.0f, 0.0f, 1.0f},
|
|
};
|
|
|
|
gushort indices[] = {
|
|
0, 1, 2, 0, 2, 3,
|
|
};
|
|
|
|
static gboolean
|
|
create_sampler (GstVulkanFullScreenQuad * self, GError ** error)
|
|
{
|
|
/* *INDENT-OFF* */
|
|
VkSamplerCreateInfo samplerInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
|
.magFilter = VK_FILTER_LINEAR,
|
|
.minFilter = VK_FILTER_LINEAR,
|
|
.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
|
|
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
|
|
.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
|
|
.anisotropyEnable = VK_FALSE,
|
|
.maxAnisotropy = 1,
|
|
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
|
.unnormalizedCoordinates = VK_FALSE,
|
|
.compareEnable = VK_FALSE,
|
|
.compareOp = VK_COMPARE_OP_ALWAYS,
|
|
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
|
|
.mipLodBias = 0.0f,
|
|
.minLod = 0.0f,
|
|
.maxLod = 0.0f
|
|
};
|
|
/* *INDENT-ON* */
|
|
VkSampler sampler;
|
|
VkResult err;
|
|
|
|
err =
|
|
vkCreateSampler (self->queue->device->device, &samplerInfo, NULL,
|
|
&sampler);
|
|
if (gst_vulkan_error_to_g_error (err, error, "vkCreateSampler") < 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
self->sampler = gst_vulkan_handle_new_wrapped (self->queue->device,
|
|
GST_VULKAN_HANDLE_TYPE_SAMPLER, (GstVulkanHandleTypedef) sampler,
|
|
gst_vulkan_handle_free_sampler, NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GstVulkanDescriptorSet *
|
|
get_and_update_descriptor_set (GstVulkanFullScreenQuad * self,
|
|
GstVulkanImageView ** views, GError ** error)
|
|
{
|
|
GstVulkanFullScreenQuadPrivate *priv = GET_PRIV (self);
|
|
GstVulkanDescriptorSet *set;
|
|
|
|
if (!self->sampler)
|
|
if (!create_sampler (self, error))
|
|
return NULL;
|
|
|
|
if (!(set =
|
|
gst_vulkan_descriptor_cache_acquire (self->descriptor_cache, error)))
|
|
return NULL;
|
|
|
|
{
|
|
VkWriteDescriptorSet writes[GST_VIDEO_MAX_PLANES + 1];
|
|
VkDescriptorImageInfo image_info[GST_VIDEO_MAX_PLANES];
|
|
VkDescriptorBufferInfo buffer_info;
|
|
int write_n = 0;
|
|
int i;
|
|
|
|
/* *INDENT-OFF* */
|
|
if (priv->uniforms) {
|
|
buffer_info = (VkDescriptorBufferInfo) {
|
|
.buffer = ((GstVulkanBufferMemory *) priv->uniforms)->buffer,
|
|
.offset = 0,
|
|
.range = priv->uniform_size
|
|
};
|
|
|
|
writes[write_n++] = (VkWriteDescriptorSet) {
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.pNext = NULL,
|
|
.dstSet = set->set,
|
|
.dstBinding = 0,
|
|
.dstArrayElement = 0,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.descriptorCount = 1,
|
|
.pBufferInfo = &buffer_info
|
|
};
|
|
}
|
|
|
|
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->in_info); i++) {
|
|
image_info[i] = (VkDescriptorImageInfo) {
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
|
.imageView = views[i]->view,
|
|
.sampler = (VkSampler) self->sampler->handle
|
|
};
|
|
|
|
writes[write_n++] = (VkWriteDescriptorSet) {
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.pNext = NULL,
|
|
.dstSet = set->set,
|
|
.dstBinding = i + 1,
|
|
.dstArrayElement = 0,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.descriptorCount = 1,
|
|
.pImageInfo = &image_info[i]
|
|
};
|
|
}
|
|
/* *INDENT-ON* */
|
|
vkUpdateDescriptorSets (self->queue->device->device, write_n, writes, 0,
|
|
NULL);
|
|
}
|
|
|
|
return set;
|
|
}
|
|
|
|
static gboolean
|
|
create_descriptor_set_layout (GstVulkanFullScreenQuad * self, GError ** error)
|
|
{
|
|
VkDescriptorSetLayoutBinding bindings[GST_VIDEO_MAX_PLANES + 1] = { {0,} };
|
|
VkDescriptorSetLayoutCreateInfo layout_info;
|
|
VkDescriptorSetLayout descriptor_set_layout;
|
|
int descriptor_n = 0;
|
|
VkResult err;
|
|
int i;
|
|
|
|
/* *INDENT-OFF* */
|
|
bindings[descriptor_n++] = (VkDescriptorSetLayoutBinding) {
|
|
.binding = 0,
|
|
.descriptorCount = 1,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.pImmutableSamplers = NULL,
|
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
|
|
};
|
|
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->in_info); i++) {
|
|
bindings[descriptor_n++] = (VkDescriptorSetLayoutBinding) {
|
|
.binding = i+1,
|
|
.descriptorCount = 1,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.pImmutableSamplers = NULL,
|
|
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
|
|
};
|
|
};
|
|
|
|
layout_info = (VkDescriptorSetLayoutCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.bindingCount = descriptor_n,
|
|
.pBindings = bindings
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
err =
|
|
vkCreateDescriptorSetLayout (self->queue->device->device, &layout_info,
|
|
NULL, &descriptor_set_layout);
|
|
if (gst_vulkan_error_to_g_error (err, error,
|
|
"vkCreateDescriptorSetLayout") < 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
self->descriptor_set_layout =
|
|
gst_vulkan_handle_new_wrapped (self->queue->device,
|
|
GST_VULKAN_HANDLE_TYPE_DESCRIPTOR_SET_LAYOUT,
|
|
(GstVulkanHandleTypedef) descriptor_set_layout,
|
|
gst_vulkan_handle_free_descriptor_set_layout, NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
create_pipeline_layout (GstVulkanFullScreenQuad * self, GError ** error)
|
|
{
|
|
VkPipelineLayoutCreateInfo pipeline_layout_info;
|
|
VkPipelineLayout pipeline_layout;
|
|
VkResult err;
|
|
|
|
if (!self->descriptor_set_layout)
|
|
if (!create_descriptor_set_layout (self, error))
|
|
return FALSE;
|
|
|
|
/* *INDENT-OFF* */
|
|
pipeline_layout_info = (VkPipelineLayoutCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.setLayoutCount = 1,
|
|
.pSetLayouts = (VkDescriptorSetLayout *) &self->descriptor_set_layout->handle,
|
|
.pushConstantRangeCount = 0,
|
|
.pPushConstantRanges = NULL,
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
err =
|
|
vkCreatePipelineLayout (self->queue->device->device,
|
|
&pipeline_layout_info, NULL, &pipeline_layout);
|
|
if (gst_vulkan_error_to_g_error (err, error, "vkCreatePipelineLayout") < 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
self->pipeline_layout = gst_vulkan_handle_new_wrapped (self->queue->device,
|
|
GST_VULKAN_HANDLE_TYPE_PIPELINE_LAYOUT,
|
|
(GstVulkanHandleTypedef) pipeline_layout,
|
|
gst_vulkan_handle_free_pipeline_layout, NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
create_render_pass (GstVulkanFullScreenQuad * self, GError ** error)
|
|
{
|
|
VkAttachmentDescription color_attachments[GST_VIDEO_MAX_PLANES];
|
|
VkAttachmentReference color_attachment_refs[GST_VIDEO_MAX_PLANES];
|
|
VkRenderPassCreateInfo render_pass_info;
|
|
VkSubpassDescription subpass;
|
|
VkRenderPass render_pass;
|
|
VkResult err;
|
|
int i;
|
|
|
|
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->out_info); i++) {
|
|
/* *INDENT-OFF* */
|
|
color_attachments[i] = (VkAttachmentDescription) {
|
|
.format = gst_vulkan_format_from_video_info (&self->out_info, i),
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
|
/* FIXME: share this between elements to avoid pipeline barriers */
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
|
};
|
|
|
|
color_attachment_refs[i] = (VkAttachmentReference) {
|
|
.attachment = i,
|
|
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
|
};
|
|
/* *INDENT-ON* */
|
|
}
|
|
|
|
/* *INDENT-OFF* */
|
|
subpass = (VkSubpassDescription) {
|
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
.colorAttachmentCount = GST_VIDEO_INFO_N_PLANES (&self->out_info),
|
|
.pColorAttachments = color_attachment_refs
|
|
};
|
|
|
|
render_pass_info = (VkRenderPassCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.attachmentCount = GST_VIDEO_INFO_N_PLANES (&self->out_info),
|
|
.pAttachments = color_attachments,
|
|
.subpassCount = 1,
|
|
.pSubpasses = &subpass
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
err =
|
|
vkCreateRenderPass (self->queue->device->device, &render_pass_info, NULL,
|
|
&render_pass);
|
|
if (gst_vulkan_error_to_g_error (err, error, "vkCreateRenderPass") < 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
self->render_pass = gst_vulkan_handle_new_wrapped (self->queue->device,
|
|
GST_VULKAN_HANDLE_TYPE_RENDER_PASS,
|
|
(GstVulkanHandleTypedef) render_pass,
|
|
gst_vulkan_handle_free_render_pass, NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
create_pipeline (GstVulkanFullScreenQuad * self, GError ** error)
|
|
{
|
|
GstVulkanFullScreenQuadPrivate *priv = GET_PRIV (self);
|
|
VkVertexInputBindingDescription vertex_binding;
|
|
VkVertexInputAttributeDescription attribute_descriptions[2];
|
|
VkPipelineShaderStageCreateInfo shader_create_info[2];
|
|
VkPipelineVertexInputStateCreateInfo vertex_input_info;
|
|
VkPipelineInputAssemblyStateCreateInfo input_assembly;
|
|
VkPipelineViewportStateCreateInfo viewport_state;
|
|
VkPipelineRasterizationStateCreateInfo rasterizer;
|
|
VkPipelineMultisampleStateCreateInfo multisampling;
|
|
VkPipelineColorBlendAttachmentState
|
|
color_blend_attachments[GST_VIDEO_MAX_PLANES];
|
|
VkPipelineColorBlendStateCreateInfo color_blending;
|
|
VkGraphicsPipelineCreateInfo pipeline_create_info;
|
|
VkPipeline pipeline;
|
|
VkResult err;
|
|
|
|
if (!priv->vert || !priv->frag) {
|
|
g_set_error_literal (error, GST_VULKAN_ERROR,
|
|
VK_ERROR_INITIALIZATION_FAILED, "Missing shader information");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!self->pipeline_layout)
|
|
if (!create_pipeline_layout (self, error))
|
|
return FALSE;
|
|
|
|
if (!self->render_pass)
|
|
if (!create_render_pass (self, error))
|
|
return FALSE;
|
|
|
|
/* *INDENT-OFF* */
|
|
shader_create_info[0] = (VkPipelineShaderStageCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
|
.module = (VkShaderModule) priv->vert->handle,
|
|
.pName = "main"
|
|
};
|
|
|
|
shader_create_info[1] = (VkPipelineShaderStageCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
.module = (VkShaderModule) priv->frag->handle,
|
|
.pName = "main"
|
|
};
|
|
|
|
/* *INDENT-OFF* */
|
|
vertex_binding = (VkVertexInputBindingDescription) {
|
|
.binding = 0,
|
|
.stride = sizeof (struct Vertex),
|
|
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
|
|
};
|
|
|
|
attribute_descriptions[0] = (VkVertexInputAttributeDescription) {
|
|
.binding = 0,
|
|
.location = 0,
|
|
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
|
.offset = G_STRUCT_OFFSET (struct Vertex, x)
|
|
};
|
|
attribute_descriptions[1] = (VkVertexInputAttributeDescription) {
|
|
.binding = 0,
|
|
.location = 1,
|
|
.format = VK_FORMAT_R32G32_SFLOAT,
|
|
.offset = G_STRUCT_OFFSET (struct Vertex, s)
|
|
};
|
|
|
|
vertex_input_info = (VkPipelineVertexInputStateCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.vertexBindingDescriptionCount = 1,
|
|
.pVertexBindingDescriptions = &vertex_binding,
|
|
.vertexAttributeDescriptionCount = 2,
|
|
.pVertexAttributeDescriptions = attribute_descriptions,
|
|
};
|
|
|
|
input_assembly = (VkPipelineInputAssemblyStateCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
|
|
.primitiveRestartEnable = VK_FALSE
|
|
};
|
|
|
|
viewport_state = (VkPipelineViewportStateCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.viewportCount = 1,
|
|
.pViewports = &(VkViewport) {
|
|
.x = 0.0f,
|
|
.y = 0.0f,
|
|
.width = (float) GST_VIDEO_INFO_WIDTH (&self->out_info),
|
|
.height = (float) GST_VIDEO_INFO_HEIGHT (&self->out_info),
|
|
.minDepth = 0.0f,
|
|
.maxDepth = 1.0f
|
|
},
|
|
.scissorCount = 1,
|
|
.pScissors = &(VkRect2D) {
|
|
.offset = { 0, 0 },
|
|
.extent = {
|
|
GST_VIDEO_INFO_WIDTH (&self->out_info),
|
|
GST_VIDEO_INFO_HEIGHT (&self->out_info)
|
|
}
|
|
}
|
|
};
|
|
|
|
rasterizer = (VkPipelineRasterizationStateCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.depthClampEnable = VK_FALSE,
|
|
.rasterizerDiscardEnable = VK_FALSE,
|
|
.polygonMode = VK_POLYGON_MODE_FILL,
|
|
.lineWidth = 1.0f,
|
|
.cullMode = VK_CULL_MODE_NONE,
|
|
.frontFace = VK_FRONT_FACE_CLOCKWISE,
|
|
.depthBiasEnable = VK_FALSE
|
|
};
|
|
|
|
multisampling = (VkPipelineMultisampleStateCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.sampleShadingEnable = VK_FALSE,
|
|
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT
|
|
};
|
|
|
|
color_blend_attachments[0] = (VkPipelineColorBlendAttachmentState) {
|
|
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
|
.blendEnable = VK_FALSE
|
|
};
|
|
color_blend_attachments[1] = (VkPipelineColorBlendAttachmentState) {
|
|
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
|
.blendEnable = VK_FALSE
|
|
};
|
|
color_blend_attachments[2] = (VkPipelineColorBlendAttachmentState) {
|
|
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
|
.blendEnable = VK_FALSE
|
|
};
|
|
color_blend_attachments[3] = (VkPipelineColorBlendAttachmentState) {
|
|
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
|
.blendEnable = VK_FALSE
|
|
};
|
|
|
|
color_blending = (VkPipelineColorBlendStateCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.logicOpEnable = VK_FALSE,
|
|
.logicOp = VK_LOGIC_OP_COPY,
|
|
.attachmentCount = GST_VIDEO_INFO_N_PLANES (&self->out_info),
|
|
.pAttachments = color_blend_attachments,
|
|
.blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f }
|
|
};
|
|
|
|
pipeline_create_info = (VkGraphicsPipelineCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.stageCount = 2,
|
|
.pStages = shader_create_info,
|
|
.pVertexInputState = &vertex_input_info,
|
|
.pInputAssemblyState = &input_assembly,
|
|
.pViewportState = &viewport_state,
|
|
.pRasterizationState = &rasterizer,
|
|
.pMultisampleState = &multisampling,
|
|
.pColorBlendState = &color_blending,
|
|
.layout = (VkPipelineLayout) self->pipeline_layout->handle,
|
|
.renderPass = (VkRenderPass) self->render_pass->handle,
|
|
.subpass = 0,
|
|
.basePipelineHandle = VK_NULL_HANDLE
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
err =
|
|
vkCreateGraphicsPipelines (self->queue->device->device, VK_NULL_HANDLE, 1,
|
|
&pipeline_create_info, NULL, &pipeline);
|
|
if (gst_vulkan_error_to_g_error (err, error, "vkCreateGraphicsPipelines") < 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
self->graphics_pipeline = gst_vulkan_handle_new_wrapped (self->queue->device,
|
|
GST_VULKAN_HANDLE_TYPE_PIPELINE, (GstVulkanHandleTypedef) pipeline,
|
|
gst_vulkan_handle_free_pipeline, NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
create_descriptor_pool (GstVulkanFullScreenQuad * self, GError ** error)
|
|
{
|
|
GstVulkanFullScreenQuadPrivate *priv = GET_PRIV (self);
|
|
VkDescriptorPoolCreateInfo pool_info;
|
|
gsize max_sets = 32; /* FIXME: don't hardcode this! */
|
|
guint n_pools = 1;
|
|
VkDescriptorPoolSize pool_sizes[2];
|
|
VkDescriptorPool pool;
|
|
GstVulkanDescriptorPool *ret;
|
|
VkResult err;
|
|
|
|
/* *INDENT-OFF* */
|
|
pool_sizes[0] = (VkDescriptorPoolSize) {
|
|
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.descriptorCount = max_sets * GST_VIDEO_INFO_N_PLANES (&self->in_info),
|
|
};
|
|
|
|
if (priv->uniforms) {
|
|
pool_sizes[1] = (VkDescriptorPoolSize) {
|
|
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.descriptorCount = max_sets
|
|
};
|
|
n_pools++;
|
|
}
|
|
|
|
pool_info = (VkDescriptorPoolCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
|
|
.poolSizeCount = n_pools,
|
|
.pPoolSizes = pool_sizes,
|
|
.maxSets = max_sets
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
err =
|
|
vkCreateDescriptorPool (self->queue->device->device, &pool_info, NULL,
|
|
&pool);
|
|
if (gst_vulkan_error_to_g_error (err, error, "vkCreateDescriptorPool") < 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
ret =
|
|
gst_vulkan_descriptor_pool_new_wrapped (self->queue->device, pool,
|
|
max_sets);
|
|
self->descriptor_cache =
|
|
gst_vulkan_descriptor_cache_new (ret, 1, &self->descriptor_set_layout);
|
|
gst_object_unref (ret);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
create_framebuffer (GstVulkanFullScreenQuad * self, GstVulkanImageView ** views,
|
|
GError ** error)
|
|
{
|
|
VkImageView attachments[GST_VIDEO_MAX_PLANES] = { 0, };
|
|
VkFramebufferCreateInfo framebuffer_info;
|
|
VkFramebuffer framebuffer;
|
|
VkResult err;
|
|
int i;
|
|
|
|
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->out_info); i++) {
|
|
attachments[i] = views[i]->view;
|
|
}
|
|
|
|
/* *INDENT-OFF* */
|
|
framebuffer_info = (VkFramebufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
.pNext = NULL,
|
|
.renderPass = (VkRenderPass) self->render_pass->handle,
|
|
.attachmentCount = GST_VIDEO_INFO_N_PLANES (&self->out_info),
|
|
.pAttachments = attachments,
|
|
.width = GST_VIDEO_INFO_WIDTH (&self->out_info),
|
|
.height = GST_VIDEO_INFO_HEIGHT (&self->out_info),
|
|
.layers = 1
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
err =
|
|
vkCreateFramebuffer (self->queue->device->device, &framebuffer_info, NULL,
|
|
&framebuffer);
|
|
if (gst_vulkan_error_to_g_error (err, error, "vkCreateFramebuffer") < 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
self->framebuffer = gst_vulkan_handle_new_wrapped (self->queue->device,
|
|
GST_VULKAN_HANDLE_TYPE_FRAMEBUFFER, (GstVulkanHandleTypedef) framebuffer,
|
|
gst_vulkan_handle_free_framebuffer, NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#define LAST_FENCE_OR_ALWAYS_SIGNALLED(self,device) \
|
|
self->last_fence ? gst_vulkan_fence_ref (self->last_fence) : gst_vulkan_fence_new_always_signalled (device)
|
|
|
|
GstVulkanFence *
|
|
gst_vulkan_full_screen_quad_get_last_fence (GstVulkanFullScreenQuad * self)
|
|
{
|
|
g_return_val_if_fail (GST_IS_VULKAN_FULL_SCREEN_QUAD (self), NULL);
|
|
|
|
return LAST_FENCE_OR_ALWAYS_SIGNALLED (self, self->queue->device);
|
|
}
|
|
|
|
static void
|
|
clear_descriptor_set (GstVulkanFullScreenQuad * self)
|
|
{
|
|
GstVulkanFence *last_fence =
|
|
LAST_FENCE_OR_ALWAYS_SIGNALLED (self, self->queue->device);
|
|
|
|
if (self->descriptor_set)
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, last_fence,
|
|
gst_vulkan_trash_mini_object_unref,
|
|
(GstMiniObject *) self->descriptor_set));
|
|
self->descriptor_set = NULL;
|
|
|
|
gst_vulkan_fence_unref (last_fence);
|
|
}
|
|
|
|
static void
|
|
clear_framebuffer (GstVulkanFullScreenQuad * self)
|
|
{
|
|
GstVulkanFence *last_fence =
|
|
LAST_FENCE_OR_ALWAYS_SIGNALLED (self, self->queue->device);
|
|
|
|
if (self->framebuffer)
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, last_fence,
|
|
gst_vulkan_trash_mini_object_unref,
|
|
(GstMiniObject *) self->framebuffer));
|
|
self->framebuffer = NULL;
|
|
|
|
gst_vulkan_fence_unref (last_fence);
|
|
}
|
|
|
|
static void
|
|
clear_command_pool (GstVulkanFullScreenQuad * self)
|
|
{
|
|
GstVulkanFence *last_fence =
|
|
LAST_FENCE_OR_ALWAYS_SIGNALLED (self, self->queue->device);
|
|
|
|
if (self->cmd_pool)
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, last_fence,
|
|
gst_vulkan_trash_object_unref, (GstObject *) self->cmd_pool));
|
|
self->cmd_pool = NULL;
|
|
|
|
gst_vulkan_fence_unref (last_fence);
|
|
}
|
|
|
|
static void
|
|
clear_sampler (GstVulkanFullScreenQuad * self)
|
|
{
|
|
GstVulkanFence *last_fence =
|
|
LAST_FENCE_OR_ALWAYS_SIGNALLED (self, self->queue->device);
|
|
|
|
if (self->sampler)
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, last_fence,
|
|
gst_vulkan_trash_mini_object_unref,
|
|
(GstMiniObject *) self->sampler));
|
|
self->sampler = NULL;
|
|
|
|
gst_vulkan_fence_unref (last_fence);
|
|
}
|
|
|
|
static void
|
|
clear_descriptor_cache (GstVulkanFullScreenQuad * self)
|
|
{
|
|
GstVulkanFence *last_fence =
|
|
LAST_FENCE_OR_ALWAYS_SIGNALLED (self, self->queue->device);
|
|
|
|
if (self->descriptor_cache)
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, last_fence,
|
|
gst_vulkan_trash_object_unref,
|
|
(GstObject *) self->descriptor_cache));
|
|
self->descriptor_cache = NULL;
|
|
|
|
gst_vulkan_fence_unref (last_fence);
|
|
}
|
|
|
|
static void
|
|
clear_shaders (GstVulkanFullScreenQuad * self)
|
|
{
|
|
GstVulkanFullScreenQuadPrivate *priv = GET_PRIV (self);
|
|
GstVulkanFence *last_fence =
|
|
LAST_FENCE_OR_ALWAYS_SIGNALLED (self, self->queue->device);
|
|
|
|
if (priv->vert)
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, last_fence,
|
|
gst_vulkan_trash_mini_object_unref, (GstMiniObject *) priv->vert));
|
|
priv->vert = NULL;
|
|
|
|
if (priv->frag)
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, last_fence,
|
|
gst_vulkan_trash_mini_object_unref, (GstMiniObject *) priv->frag));
|
|
priv->frag = NULL;
|
|
|
|
gst_vulkan_fence_unref (last_fence);
|
|
}
|
|
|
|
static void
|
|
clear_uniform_data (GstVulkanFullScreenQuad * self)
|
|
{
|
|
GstVulkanFullScreenQuadPrivate *priv = GET_PRIV (self);
|
|
GstVulkanFence *last_fence =
|
|
LAST_FENCE_OR_ALWAYS_SIGNALLED (self, self->queue->device);
|
|
|
|
if (priv->uniforms)
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, last_fence,
|
|
gst_vulkan_trash_mini_object_unref,
|
|
(GstMiniObject *) priv->uniforms));
|
|
priv->uniforms = NULL;
|
|
priv->uniform_size = 0;
|
|
|
|
gst_vulkan_fence_unref (last_fence);
|
|
}
|
|
|
|
static void
|
|
destroy_pipeline (GstVulkanFullScreenQuad * self)
|
|
{
|
|
GstVulkanFence *last_fence =
|
|
LAST_FENCE_OR_ALWAYS_SIGNALLED (self, self->queue->device);
|
|
|
|
if (self->render_pass)
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, last_fence,
|
|
gst_vulkan_trash_mini_object_unref,
|
|
(GstMiniObject *) self->render_pass));
|
|
self->render_pass = NULL;
|
|
if (self->pipeline_layout)
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, last_fence,
|
|
gst_vulkan_trash_mini_object_unref,
|
|
(GstMiniObject *) self->pipeline_layout));
|
|
self->pipeline_layout = NULL;
|
|
if (self->graphics_pipeline)
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, last_fence,
|
|
gst_vulkan_trash_mini_object_unref,
|
|
(GstMiniObject *) self->graphics_pipeline));
|
|
self->graphics_pipeline = NULL;
|
|
if (self->descriptor_set_layout)
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, last_fence,
|
|
gst_vulkan_trash_mini_object_unref,
|
|
(GstMiniObject *) self->descriptor_set_layout));
|
|
self->descriptor_set_layout = NULL;
|
|
|
|
gst_vulkan_fence_unref (last_fence);
|
|
|
|
gst_vulkan_trash_list_gc (self->trash_list);
|
|
}
|
|
|
|
void
|
|
gst_vulkan_full_screen_quad_init (GstVulkanFullScreenQuad * self)
|
|
{
|
|
self->trash_list = gst_vulkan_trash_fence_list_new ();
|
|
}
|
|
|
|
GstVulkanFullScreenQuad *
|
|
gst_vulkan_full_screen_quad_new (GstVulkanQueue * queue)
|
|
{
|
|
GstVulkanFullScreenQuad *self;
|
|
|
|
g_return_val_if_fail (GST_IS_VULKAN_QUEUE (queue), NULL);
|
|
|
|
self = g_object_new (GST_TYPE_VULKAN_FULL_SCREEN_QUAD, NULL);
|
|
self->queue = gst_object_ref (queue);
|
|
|
|
return self;
|
|
}
|
|
|
|
static void
|
|
gst_vulkan_full_screen_quad_finalize (GObject * object)
|
|
{
|
|
GstVulkanFullScreenQuad *self = GST_VULKAN_FULL_SCREEN_QUAD (object);
|
|
GstVulkanFullScreenQuadPrivate *priv = GET_PRIV (self);
|
|
|
|
destroy_pipeline (self);
|
|
clear_command_pool (self);
|
|
clear_sampler (self);
|
|
clear_framebuffer (self);
|
|
clear_descriptor_set (self);
|
|
clear_descriptor_cache (self);
|
|
clear_shaders (self);
|
|
clear_uniform_data (self);
|
|
|
|
gst_vulkan_trash_list_wait (self->trash_list, -1);
|
|
gst_vulkan_trash_list_gc (self->trash_list);
|
|
gst_clear_object (&self->trash_list);
|
|
|
|
gst_clear_mini_object (((GstMiniObject **) & priv->vertices));
|
|
gst_clear_mini_object (((GstMiniObject **) & priv->indices));
|
|
|
|
gst_clear_mini_object (((GstMiniObject **) & self->last_fence));
|
|
|
|
gst_clear_object (&self->queue);
|
|
|
|
gst_clear_buffer (&priv->inbuf);
|
|
gst_clear_buffer (&priv->outbuf);
|
|
|
|
G_OBJECT_CLASS (gst_vulkan_full_screen_quad_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gst_vulkan_full_screen_quad_class_init (GstVulkanFullScreenQuadClass * klass)
|
|
{
|
|
GObjectClass *obj_class = G_OBJECT_CLASS (klass);
|
|
|
|
obj_class->finalize = gst_vulkan_full_screen_quad_finalize;
|
|
}
|
|
|
|
gboolean
|
|
gst_vulkan_full_screen_quad_set_info (GstVulkanFullScreenQuad * self,
|
|
GstVideoInfo * in_info, GstVideoInfo * out_info)
|
|
{
|
|
self->out_info = *out_info;
|
|
self->in_info = *in_info;
|
|
|
|
destroy_pipeline (self);
|
|
clear_framebuffer (self);
|
|
clear_descriptor_set (self);
|
|
clear_descriptor_cache (self);
|
|
clear_uniform_data (self);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gst_vulkan_full_screen_quad_set_input_buffer (GstVulkanFullScreenQuad * self,
|
|
GstBuffer * buffer, GError ** error)
|
|
{
|
|
GstVulkanFullScreenQuadPrivate *priv;
|
|
|
|
g_return_val_if_fail (GST_IS_VULKAN_FULL_SCREEN_QUAD (self), FALSE);
|
|
|
|
priv = GET_PRIV (self);
|
|
|
|
gst_buffer_replace (&priv->inbuf, buffer);
|
|
clear_descriptor_set (self);
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gst_vulkan_full_screen_quad_set_output_buffer (GstVulkanFullScreenQuad * self,
|
|
GstBuffer * buffer, GError ** error)
|
|
{
|
|
GstVulkanFullScreenQuadPrivate *priv;
|
|
|
|
g_return_val_if_fail (GST_IS_VULKAN_FULL_SCREEN_QUAD (self), FALSE);
|
|
|
|
priv = GET_PRIV (self);
|
|
|
|
gst_buffer_replace (&priv->outbuf, buffer);
|
|
clear_framebuffer (self);
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gst_vulkan_full_screen_quad_set_shaders (GstVulkanFullScreenQuad * self,
|
|
GstVulkanHandle * vert, GstVulkanHandle * frag)
|
|
{
|
|
GstVulkanFullScreenQuadPrivate *priv;
|
|
|
|
g_return_val_if_fail (GST_IS_VULKAN_FULL_SCREEN_QUAD (self), FALSE);
|
|
g_return_val_if_fail (vert != NULL, FALSE);
|
|
g_return_val_if_fail (vert->type == GST_VULKAN_HANDLE_TYPE_SHADER, FALSE);
|
|
g_return_val_if_fail (frag != NULL, FALSE);
|
|
g_return_val_if_fail (frag->type == GST_VULKAN_HANDLE_TYPE_SHADER, FALSE);
|
|
|
|
priv = GET_PRIV (self);
|
|
|
|
clear_shaders (self);
|
|
destroy_pipeline (self);
|
|
|
|
priv->vert = gst_vulkan_handle_ref (vert);
|
|
priv->frag = gst_vulkan_handle_ref (frag);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gst_vulkan_full_screen_quad_set_uniform_buffer (GstVulkanFullScreenQuad * self,
|
|
GstMemory * uniforms, GError ** error)
|
|
{
|
|
GstVulkanFullScreenQuadPrivate *priv;
|
|
|
|
g_return_val_if_fail (GST_IS_VULKAN_FULL_SCREEN_QUAD (self), FALSE);
|
|
g_return_val_if_fail (uniforms == NULL
|
|
|| gst_is_vulkan_buffer_memory (uniforms), FALSE);
|
|
|
|
priv = GET_PRIV (self);
|
|
|
|
clear_uniform_data (self);
|
|
if (uniforms) {
|
|
priv->uniforms = gst_memory_ref (uniforms);
|
|
priv->uniform_size = gst_memory_get_sizes (uniforms, NULL, NULL);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GstVulkanImageMemory *
|
|
peek_image_from_buffer (GstBuffer * buffer, guint i)
|
|
{
|
|
GstMemory *mem = gst_buffer_peek_memory (buffer, i);
|
|
g_return_val_if_fail (gst_is_vulkan_image_memory (mem), NULL);
|
|
return (GstVulkanImageMemory *) mem;
|
|
}
|
|
|
|
static gboolean
|
|
ensure_vertex_data (GstVulkanFullScreenQuad * self, GError ** error)
|
|
{
|
|
GstVulkanFullScreenQuadPrivate *priv = GET_PRIV (self);
|
|
GstMapInfo map_info;
|
|
|
|
if (!priv->vertices) {
|
|
priv->vertices = gst_vulkan_buffer_memory_alloc (self->queue->device,
|
|
sizeof (vertices), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
}
|
|
|
|
if (!gst_memory_map (priv->vertices, &map_info, GST_MAP_WRITE)) {
|
|
g_set_error_literal (error, GST_VULKAN_ERROR, VK_ERROR_MEMORY_MAP_FAILED,
|
|
"Failed to map memory");
|
|
goto failure;
|
|
}
|
|
|
|
memcpy (map_info.data, vertices, map_info.size);
|
|
gst_memory_unmap (priv->vertices, &map_info);
|
|
|
|
if (!priv->indices) {
|
|
priv->indices = gst_vulkan_buffer_memory_alloc (self->queue->device,
|
|
sizeof (indices), VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
}
|
|
|
|
if (!gst_memory_map (priv->indices, &map_info, GST_MAP_WRITE)) {
|
|
g_set_error_literal (error, GST_VULKAN_ERROR, VK_ERROR_MEMORY_MAP_FAILED,
|
|
"Failed to map memory");
|
|
goto failure;
|
|
}
|
|
|
|
memcpy (map_info.data, indices, map_info.size);
|
|
gst_memory_unmap (priv->indices, &map_info);
|
|
|
|
priv->n_indices = G_N_ELEMENTS (indices);
|
|
|
|
return TRUE;
|
|
|
|
failure:
|
|
if (priv->vertices)
|
|
gst_memory_unref (priv->vertices);
|
|
priv->vertices = NULL;
|
|
if (priv->indices)
|
|
gst_memory_unref (priv->indices);
|
|
priv->indices = NULL;
|
|
priv->n_indices = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean
|
|
gst_vulkan_full_screen_quad_draw (GstVulkanFullScreenQuad * self,
|
|
GError ** error)
|
|
{
|
|
GstVulkanCommandBuffer *cmd = NULL;
|
|
GstVulkanFence *fence = NULL;
|
|
VkResult err;
|
|
|
|
g_return_val_if_fail (GST_IS_VULKAN_FULL_SCREEN_QUAD (self), FALSE);
|
|
|
|
fence = gst_vulkan_device_create_fence (self->queue->device, error);
|
|
if (!fence)
|
|
goto error;
|
|
|
|
if (!gst_vulkan_full_screen_quad_prepare_draw (self, fence, error))
|
|
goto error;
|
|
|
|
if (!(cmd = gst_vulkan_command_pool_create (self->cmd_pool, error)))
|
|
goto error;
|
|
|
|
{
|
|
VkCommandBufferBeginInfo cmd_buf_info = { 0, };
|
|
|
|
/* *INDENT-OFF* */
|
|
cmd_buf_info = (VkCommandBufferBeginInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
.pNext = NULL,
|
|
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
|
.pInheritanceInfo = NULL
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
gst_vulkan_command_buffer_lock (cmd);
|
|
err = vkBeginCommandBuffer (cmd->cmd, &cmd_buf_info);
|
|
if (gst_vulkan_error_to_g_error (err, error, "vkBeginCommandBuffer") < 0)
|
|
goto unlock_error;
|
|
}
|
|
|
|
if (!gst_vulkan_full_screen_quad_fill_command_buffer (self, cmd, fence,
|
|
error))
|
|
goto unlock_error;
|
|
|
|
err = vkEndCommandBuffer (cmd->cmd);
|
|
gst_vulkan_command_buffer_unlock (cmd);
|
|
if (gst_vulkan_error_to_g_error (err, error, "vkEndCommandBuffer") < 0)
|
|
goto error;
|
|
|
|
if (!gst_vulkan_full_screen_quad_submit (self, cmd, fence, error))
|
|
goto error;
|
|
|
|
gst_vulkan_fence_unref (fence);
|
|
|
|
return TRUE;
|
|
|
|
unlock_error:
|
|
gst_vulkan_command_buffer_unlock (cmd);
|
|
|
|
error:
|
|
gst_clear_mini_object ((GstMiniObject **) & cmd);
|
|
gst_clear_mini_object ((GstMiniObject **) & fence);
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean
|
|
gst_vulkan_full_screen_quad_prepare_draw (GstVulkanFullScreenQuad * self,
|
|
GstVulkanFence * fence, GError ** error)
|
|
{
|
|
GstVulkanFullScreenQuadPrivate *priv;
|
|
GstVulkanImageView *in_views[GST_VIDEO_MAX_PLANES] = { NULL, };
|
|
GstVulkanImageView *out_views[GST_VIDEO_MAX_PLANES] = { NULL, };
|
|
int i;
|
|
|
|
g_return_val_if_fail (GST_IS_VULKAN_FULL_SCREEN_QUAD (self), FALSE);
|
|
g_return_val_if_fail (fence != NULL, FALSE);
|
|
|
|
priv = GET_PRIV (self);
|
|
|
|
if (!self->graphics_pipeline)
|
|
if (!create_pipeline (self, error))
|
|
return FALSE;
|
|
|
|
if (!ensure_vertex_data (self, error))
|
|
goto error;
|
|
|
|
if (!self->descriptor_cache)
|
|
if (!create_descriptor_pool (self, error))
|
|
goto error;
|
|
|
|
if (!self->descriptor_set) {
|
|
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->in_info); i++) {
|
|
GstVulkanImageMemory *img_mem = peek_image_from_buffer (priv->inbuf, i);
|
|
if (!gst_is_vulkan_image_memory ((GstMemory *) img_mem)) {
|
|
g_set_error_literal (error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
|
|
"Input memory must be a GstVulkanImageMemory");
|
|
goto error;
|
|
}
|
|
in_views[i] = get_or_create_image_view (img_mem);
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, fence,
|
|
gst_vulkan_trash_mini_object_unref,
|
|
(GstMiniObject *) in_views[i]));
|
|
}
|
|
if (!(self->descriptor_set =
|
|
get_and_update_descriptor_set (self, in_views, error)))
|
|
goto error;
|
|
}
|
|
|
|
if (!self->framebuffer) {
|
|
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->out_info); i++) {
|
|
GstVulkanImageMemory *img_mem = peek_image_from_buffer (priv->outbuf, i);
|
|
if (!gst_is_vulkan_image_memory ((GstMemory *) img_mem)) {
|
|
g_set_error_literal (error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
|
|
"Output memory must be a GstVulkanImageMemory");
|
|
goto error;
|
|
}
|
|
out_views[i] = get_or_create_image_view (img_mem);
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, fence,
|
|
gst_vulkan_trash_mini_object_unref,
|
|
(GstMiniObject *) out_views[i]));
|
|
}
|
|
if (!create_framebuffer (self, out_views, error))
|
|
goto error;
|
|
}
|
|
|
|
if (!self->cmd_pool)
|
|
if (!(self->cmd_pool =
|
|
gst_vulkan_queue_create_command_pool (self->queue, error)))
|
|
goto error;
|
|
|
|
return TRUE;
|
|
|
|
error:
|
|
for (i = 0; i < GST_VIDEO_MAX_PLANES; i++)
|
|
gst_clear_mini_object ((GstMiniObject **) & in_views[i]);
|
|
for (i = 0; i < GST_VIDEO_MAX_PLANES; i++)
|
|
gst_clear_mini_object ((GstMiniObject **) & out_views[i]);
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* gst_vulkan_full_screen_quad_fill_command_buffer:
|
|
* @self: a #GstVulkanFullScreenQuad
|
|
* @cmd: the #GstVulkanCommandBuffer to fill with commands
|
|
* @error: a #GError to fill on error
|
|
*
|
|
* Returns: whether @cmd could be filled with the necessary commands
|
|
*/
|
|
gboolean
|
|
gst_vulkan_full_screen_quad_fill_command_buffer (GstVulkanFullScreenQuad * self,
|
|
GstVulkanCommandBuffer * cmd, GstVulkanFence * fence, GError ** error)
|
|
{
|
|
GstVulkanFullScreenQuadPrivate *priv;
|
|
GstVulkanImageView *in_views[GST_VIDEO_MAX_PLANES] = { NULL, };
|
|
GstVulkanImageView *out_views[GST_VIDEO_MAX_PLANES] = { NULL, };
|
|
int i;
|
|
|
|
g_return_val_if_fail (GST_IS_VULKAN_FULL_SCREEN_QUAD (self), FALSE);
|
|
g_return_val_if_fail (cmd != NULL, FALSE);
|
|
g_return_val_if_fail (fence != NULL, FALSE);
|
|
|
|
priv = GET_PRIV (self);
|
|
|
|
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->in_info); i++) {
|
|
GstVulkanImageMemory *img_mem = peek_image_from_buffer (priv->inbuf, i);
|
|
if (!gst_is_vulkan_image_memory ((GstMemory *) img_mem)) {
|
|
g_set_error_literal (error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
|
|
"Input memory must be a GstVulkanImageMemory");
|
|
goto error;
|
|
}
|
|
in_views[i] = get_or_create_image_view (img_mem);
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, fence,
|
|
gst_vulkan_trash_mini_object_unref, (GstMiniObject *) in_views[i]));
|
|
}
|
|
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->out_info); i++) {
|
|
GstVulkanImageMemory *img_mem = peek_image_from_buffer (priv->outbuf, i);
|
|
if (!gst_is_vulkan_image_memory ((GstMemory *) img_mem)) {
|
|
g_set_error_literal (error, GST_VULKAN_ERROR, GST_VULKAN_FAILED,
|
|
"Output memory must be a GstVulkanImageMemory");
|
|
goto error;
|
|
}
|
|
out_views[i] = get_or_create_image_view (img_mem);
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, fence,
|
|
gst_vulkan_trash_mini_object_unref,
|
|
(GstMiniObject *) out_views[i]));
|
|
}
|
|
|
|
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->in_info); i++) {
|
|
/* *INDENT-OFF* */
|
|
VkImageMemoryBarrier in_image_memory_barrier = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
.pNext = NULL,
|
|
.srcAccessMask = in_views[i]->image->barrier.parent.access_flags,
|
|
.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
|
|
.oldLayout = in_views[i]->image->barrier.image_layout,
|
|
.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
|
/* FIXME: implement exclusive transfers */
|
|
.srcQueueFamilyIndex = 0,
|
|
.dstQueueFamilyIndex = 0,
|
|
.image = in_views[i]->image->image,
|
|
.subresourceRange = in_views[i]->image->barrier.subresource_range
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
vkCmdPipelineBarrier (cmd->cmd,
|
|
in_views[i]->image->barrier.parent.pipeline_stages,
|
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1,
|
|
&in_image_memory_barrier);
|
|
|
|
in_views[i]->image->barrier.parent.pipeline_stages =
|
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
|
in_views[i]->image->barrier.parent.access_flags =
|
|
in_image_memory_barrier.dstAccessMask;
|
|
in_views[i]->image->barrier.image_layout =
|
|
in_image_memory_barrier.newLayout;
|
|
}
|
|
|
|
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&self->out_info); i++) {
|
|
/* *INDENT-OFF* */
|
|
VkImageMemoryBarrier out_image_memory_barrier = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
.pNext = NULL,
|
|
.srcAccessMask = out_views[i]->image->barrier.parent.access_flags,
|
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
.oldLayout = out_views[i]->image->barrier.image_layout,
|
|
.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
|
/* FIXME: implement exclusive transfers */
|
|
.srcQueueFamilyIndex = 0,
|
|
.dstQueueFamilyIndex = 0,
|
|
.image = out_views[i]->image->image,
|
|
.subresourceRange = out_views[i]->image->barrier.subresource_range
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
vkCmdPipelineBarrier (cmd->cmd,
|
|
out_views[i]->image->barrier.parent.pipeline_stages,
|
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1,
|
|
&out_image_memory_barrier);
|
|
|
|
out_views[i]->image->barrier.parent.pipeline_stages =
|
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
out_views[i]->image->barrier.parent.access_flags =
|
|
out_image_memory_barrier.dstAccessMask;
|
|
out_views[i]->image->barrier.image_layout =
|
|
out_image_memory_barrier.newLayout;
|
|
}
|
|
|
|
{
|
|
/* *INDENT-OFF* */
|
|
VkClearValue clearColor = {{{ 0.0f, 0.0f, 0.0f, 1.0f }}};
|
|
VkClearValue clearColors[GST_VIDEO_MAX_PLANES] = {
|
|
clearColor, clearColor, clearColor, clearColor,
|
|
};
|
|
VkRenderPassBeginInfo render_pass_info = {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
|
.renderPass = (VkRenderPass) self->render_pass->handle,
|
|
.framebuffer = (VkFramebuffer) self->framebuffer->handle,
|
|
.renderArea.offset = { 0, 0 },
|
|
.renderArea.extent = {
|
|
GST_VIDEO_INFO_WIDTH (&self->out_info),
|
|
GST_VIDEO_INFO_HEIGHT (&self->out_info)
|
|
},
|
|
.clearValueCount = GST_VIDEO_INFO_N_PLANES (&self->out_info),
|
|
.pClearValues = clearColors,
|
|
};
|
|
/* *INDENT-ON* */
|
|
VkDeviceSize offsets[] = { 0 };
|
|
|
|
vkCmdBindDescriptorSets (cmd->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
(VkPipelineLayout) self->pipeline_layout->handle, 0, 1,
|
|
&self->descriptor_set->set, 0, NULL);
|
|
|
|
vkCmdBeginRenderPass (cmd->cmd, &render_pass_info,
|
|
VK_SUBPASS_CONTENTS_INLINE);
|
|
vkCmdBindPipeline (cmd->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
(VkPipeline) self->graphics_pipeline->handle);
|
|
vkCmdBindVertexBuffers (cmd->cmd, 0, 1,
|
|
&((GstVulkanBufferMemory *) priv->vertices)->buffer, offsets);
|
|
vkCmdBindIndexBuffer (cmd->cmd,
|
|
((GstVulkanBufferMemory *) priv->indices)->buffer, 0,
|
|
VK_INDEX_TYPE_UINT16);
|
|
vkCmdDrawIndexed (cmd->cmd, priv->n_indices, 1, 0, 0, 0);
|
|
vkCmdEndRenderPass (cmd->cmd);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
error:
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* gst_vulkan_full_screen_quad_submit:
|
|
* @self: a #GstVulkanFullScreenQuad
|
|
* @cmd: (transfer full): a #GstVulkanCommandBuffer to submit
|
|
* @fence: a #GstVulkanFence to signal on completion
|
|
* @error: a #GError to fill on error
|
|
*
|
|
* Returns: whether @cmd could be submitted to the queue
|
|
*/
|
|
gboolean
|
|
gst_vulkan_full_screen_quad_submit (GstVulkanFullScreenQuad * self,
|
|
GstVulkanCommandBuffer * cmd, GstVulkanFence * fence, GError ** error)
|
|
{
|
|
VkResult err;
|
|
|
|
g_return_val_if_fail (GST_IS_VULKAN_FULL_SCREEN_QUAD (self), FALSE);
|
|
g_return_val_if_fail (cmd != NULL, FALSE);
|
|
g_return_val_if_fail (fence != NULL, FALSE);
|
|
|
|
{
|
|
/* *INDENT-OFF* */
|
|
VkSubmitInfo submit_info = {
|
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
.pNext = NULL,
|
|
.waitSemaphoreCount = 0,
|
|
.pWaitSemaphores = NULL,
|
|
.pWaitDstStageMask = NULL,
|
|
.commandBufferCount = 1,
|
|
.pCommandBuffers = &cmd->cmd,
|
|
.signalSemaphoreCount = 0,
|
|
.pSignalSemaphores = NULL,
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
gst_vulkan_queue_submit_lock (self->queue);
|
|
err =
|
|
vkQueueSubmit (self->queue->queue, 1, &submit_info,
|
|
GST_VULKAN_FENCE_FENCE (fence));
|
|
gst_vulkan_queue_submit_unlock (self->queue);
|
|
if (gst_vulkan_error_to_g_error (err, error, "vkQueueSubmit") < 0)
|
|
goto error;
|
|
}
|
|
|
|
gst_vulkan_trash_list_add (self->trash_list,
|
|
gst_vulkan_trash_list_acquire (self->trash_list, fence,
|
|
gst_vulkan_trash_mini_object_unref, GST_MINI_OBJECT_CAST (cmd)));
|
|
|
|
gst_vulkan_trash_list_gc (self->trash_list);
|
|
|
|
if (self->last_fence)
|
|
gst_vulkan_fence_unref (self->last_fence);
|
|
self->last_fence = gst_vulkan_fence_ref (fence);
|
|
|
|
return TRUE;
|
|
|
|
error:
|
|
return FALSE;
|
|
}
|