From patchwork Fri Mar 30 14:44:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rostislav Pehlivanov X-Patchwork-Id: 8247 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.1.70 with SMTP id c67csp2974648jad; Fri, 30 Mar 2018 07:51:01 -0700 (PDT) X-Google-Smtp-Source: AIpwx485y8IRGf7+3XU7SVRIGfwnOrHrrmJV409KRcmyCXsO7ju/hMC5MI4xUaKZZfgAMU7xDBGU X-Received: by 10.28.22.2 with SMTP id 2mr2415683wmw.159.1522421461309; Fri, 30 Mar 2018 07:51:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1522421461; cv=none; d=google.com; s=arc-20160816; b=ndhG5YlLyF6hHm6slh2N3B98ZDxLT8s/cuo/gChbKx7oXvtai7Ch+vGr674DmPKkLv MMrrZu67Ry7vQqKg7VCf3uqJt4nGYylhni7D9pKesmvyRR7vE/7v3tF48kgkPrVGP3la 27C4pzEH3vpVvO5qWAAYUrzs+fiVjg8Oq1uoAn6zCYHT60PPP1Y93TgLbiCXtoO7k9t3 DFwEGorPgQodIBC7anx4jZisd//orFJsxjKCMuoKphCYadULVYncDbtLOQAjKHfS5xE5 xiRynAX8iPZd+8meUPRaxRKsDiu0rpPAFrXF4K05xoVaz/F03MLkJDRf/XWyTMDZR0Ju N5NA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to:arc-authentication-results; bh=UBk9rptos6y+0ABjAgFiDi0Gf/mLf/W/FcvqBpuMSXM=; b=IhEMhU8MWG6VQs43JFbccTsxOF9L/CAxsALWNTW2aoyhvhzIqwy2fKlaHgoTw3L2gX QsKboUfynW1XHEqua2MhyespzpXdnP/Sgp/d9fNTUl5AybjteGHqOVdXzmD6UpeFcXRI Y26q3MmyPqhi94hDxJCHJQMycJ/vwwX1oeTtTqBJSyg47wwSXqt2dkxzScL7k1ePm+SN HsvLctJxKkzeBYbFRInfOwUkuEUZpfeC7zlyQ37DPZ6uvSzVyuqzKzXczhf9fq4UNI+h KF6MdflglD04DplrTgGeyY5C2MmcykD3/0/VVQ/jI7Jrd/VFthdDTlgRlb1isUUQ7E5n eW9Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=pmw93i0b; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id p190si3070415wmp.85.2018.03.30.07.51.00; Fri, 30 Mar 2018 07:51:01 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=pmw93i0b; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id DDC5F68974E; Fri, 30 Mar 2018 17:50:39 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr0-f196.google.com (mail-wr0-f196.google.com [209.85.128.196]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 4FDEC6800E1 for ; Fri, 30 Mar 2018 17:50:33 +0300 (EEST) Received: by mail-wr0-f196.google.com with SMTP id y55so8232682wry.3 for ; Fri, 30 Mar 2018 07:50:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=9MH9diA3t89/lWm/Gs2JhO6LbXg2qeLa731t/7SVfho=; b=pmw93i0bfMmWDB5ZyK1xUm2cXgGi2C3iUnvfVUQ6+FlbEMeLGO/dhmcVeghqGX2lTx k9OEL4cbrO5XOavYiaijoKlSGoM0bfs9A8kQYbguNsVzY9Yx8alUpo8bZy5waV4xa+bV 6jR+ORxZoxwu9Q7GRDmvUrjTB4+g/CklBly9LwAm98zNF4k3vkNPrUHGlPzDS+LI1NOw Mrj1sQULtzvWnSL8FkxZqTtk++xlhrQJkILUq2VgWBX3CbeDbTweSGLT070dlIlyT2+M 7mKllC+WInnlKccwF0wwyB5nHdT1wXg7eIdtFjlOwt8aF+x3Z6glpTW5Ok/pBjHM81AF ilQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=9MH9diA3t89/lWm/Gs2JhO6LbXg2qeLa731t/7SVfho=; b=JbAUZsBHYX0Tks+Z2NcDdIQZ0LzaoDSl1UkV+vmkKyMjDNzyF07MXa634iSvwO8N2m /Aa2VPcrrKGqYXlFo2nm26LuxSE2sTotNfuNwRSZYn4bFJRulcQMrn+u17zuQGU6TIjR 20+1WWQSoDWIAUVnfLDVLiylS0V9U/UdVgGOcZBqZKBYHqRu+oycPYkjcxDU4GKKxibz jbA0dflH3kqrpLLIdEgSfTFUu2L72eHuwP+ERF187EXeLwNueYUa9JP+b1SzAK9gzRNL 1+EYFLPg0bw2EIS7XCjbjiauLzkhpZvPMyuQShe6AMvilqgqIeFfIWkhfFSENVwj/i+O /KOw== X-Gm-Message-State: AElRT7EanZ2t3nUfV2K/QAK3FEjHB1E1reknrcqX5vAj92NBUQJ7+ngn TFy5uven+CGigNucj1uRWaRZDIwT X-Received: by 10.223.157.3 with SMTP id k3mr10400154wre.179.1522421055083; Fri, 30 Mar 2018 07:44:15 -0700 (PDT) Received: from moonbase.pars.ee ([2a00:23c4:7c88:af00:c5c7:81e6:8fcc:20eb]) by smtp.gmail.com with ESMTPSA id 134sm3078842wmt.29.2018.03.30.07.44.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 30 Mar 2018 07:44:13 -0700 (PDT) From: Rostislav Pehlivanov To: ffmpeg-devel@ffmpeg.org Date: Fri, 30 Mar 2018 15:44:11 +0100 Message-Id: <20180330144411.20139-1-atomnuker@gmail.com> X-Mailer: git-send-email 2.16.3 In-Reply-To: References: Subject: [FFmpeg-devel] [PATCH] lavfi: add a Vulkan Chromatic Aberration filter X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Rostislav Pehlivanov MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This implements a simple chromatic aberration filter. The curve could use a little bit of tweaking, right now its not as curvy as it should be but nevertheless it models the imperfections of lenses. Meant to be applied on top of my previous patches. RFC quality again. Signed-off-by: Rostislav Pehlivanov --- You want something more interesting, you get something more interesting! configure | 1 + libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + libavfilter/vf_avgblur_vulkan.c | 3 - libavfilter/vf_chromaticaberration_vulkan.c | 334 ++++++++++++++++++++++++++++ libavfilter/vulkan.c | 7 +- libavfilter/vulkan.h | 2 +- 7 files changed, 342 insertions(+), 7 deletions(-) create mode 100644 libavfilter/vf_chromaticaberration_vulkan.c diff --git a/configure b/configure index 388e45fed1..577c8e0aba 100755 --- a/configure +++ b/configure @@ -3298,6 +3298,7 @@ azmq_filter_deps="libzmq" blackframe_filter_deps="gpl" boxblur_filter_deps="gpl" bs2b_filter_deps="libbs2b" +chromaticabberation_vulkan_filter_deps="vulkan libshaderc" colormatrix_filter_deps="gpl" convolution_opencl_filter_deps="opencl" convolve_filter_deps="avcodec" diff --git a/libavfilter/Makefile b/libavfilter/Makefile index f0a47320c8..4798f002a8 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -151,6 +151,7 @@ OBJS-$(CONFIG_BLEND_FILTER) += vf_blend.o framesync.o OBJS-$(CONFIG_BOXBLUR_FILTER) += vf_boxblur.o OBJS-$(CONFIG_BWDIF_FILTER) += vf_bwdif.o OBJS-$(CONFIG_CHROMAKEY_FILTER) += vf_chromakey.o +OBJS-$(CONFIG_CHROMATICABERRATION_VULKAN_FILTER) += vf_chromaticaberration_vulkan.o vulkan.o OBJS-$(CONFIG_CIESCOPE_FILTER) += vf_ciescope.o OBJS-$(CONFIG_CODECVIEW_FILTER) += vf_codecview.o OBJS-$(CONFIG_COLORBALANCE_FILTER) += vf_colorbalance.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 3cbaecd726..3baf32ae7a 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -160,6 +160,7 @@ static void register_all(void) REGISTER_FILTER(BOXBLUR, boxblur, vf); REGISTER_FILTER(BWDIF, bwdif, vf); REGISTER_FILTER(CHROMAKEY, chromakey, vf); + REGISTER_FILTER(CHROMATICABERRATION_VULKAN, chromaticaberration_vulkan, vf); REGISTER_FILTER(CIESCOPE, ciescope, vf); REGISTER_FILTER(CODECVIEW, codecview, vf); REGISTER_FILTER(COLORBALANCE, colorbalance, vf); diff --git a/libavfilter/vf_avgblur_vulkan.c b/libavfilter/vf_avgblur_vulkan.c index a2c0fddd98..cef855d891 100644 --- a/libavfilter/vf_avgblur_vulkan.c +++ b/libavfilter/vf_avgblur_vulkan.c @@ -79,9 +79,6 @@ static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in) int err; AvgBlurVulkanContext *s = ctx->priv; - /* Create sampler */ - ff_vk_init_sampler(ctx, NULL); - { /* Create the shader */ const int planes = av_pix_fmt_count_planes(s->vkctx.output_format); diff --git a/libavfilter/vf_chromaticaberration_vulkan.c b/libavfilter/vf_chromaticaberration_vulkan.c new file mode 100644 index 0000000000..e7497e7384 --- /dev/null +++ b/libavfilter/vf_chromaticaberration_vulkan.c @@ -0,0 +1,334 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/opt.h" +#include "vulkan.h" +#include "internal.h" + +typedef struct ChromaticAberrationVulkanContext { + VulkanFilterContext vkctx; + + int initialized; + AVVkExecContext exec; + AVVkBuffer shader_buf; + + /* Shader updators, must be in the main filter struct */ + VkDescriptorImageInfo input_images[3]; + VkDescriptorImageInfo output_images[3]; + + float dist_x; + float dist_y; +} ChromaticAberrationVulkanContext; + +#define RET(x) \ + do { \ + if ((err = (x)) < 0) \ + goto fail; \ + } while (0) + +static const char distort_chroma_kernel[] = { + C(0, void distort_chroma(int idx, ivec2 size, ivec2 pos) ) + C(0, { ) + C(1, vec2 p = ((vec2(pos)/vec2(size)) - 0.5f)*2.0f; ) + C(1, float d = sqrt(p.x*p.x + p.y*p.y); ) + C(1, p *= d / (d*FILTER_DIST); ) + C(1, vec4 res = texture(input_img[idx], (p/2.0f) + 0.5f); ) + C(1, imageStore(output_img[idx], pos, res); ) + C(0, } ) +}; + +static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in) +{ + int err; + ChromaticAberrationVulkanContext *s = ctx->priv; + + /* Create sampler */ + ff_vk_init_sampler(ctx, NULL, 0); + + { /* Create the shader */ + float dist_x = (s->dist_x/100.0f) + 1.0f; + float dist_y = (s->dist_y/100.0f) + 1.0f; + const int planes = av_pix_fmt_count_planes(s->vkctx.output_format); + + SPIRVShader *shd = ff_vk_init_shader(ctx, "chromaticaberration_compute", + VK_SHADER_STAGE_COMPUTE_BIT); + ff_vk_set_compute_shader_sizes(ctx, shd, (int [3]){ 16, 16, 1 }); + + VulkanDescriptorSetBinding desc_i[2] = { + { + .name = "input_img", + .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .dimensions = 2, + .elems = planes, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .updater = s->input_images, + }, + { + .name = "output_img", + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .mem_layout = "rgba8", + .mem_quali = "writeonly", + .dimensions = 2, + .elems = planes, + .stages = VK_SHADER_STAGE_COMPUTE_BIT, + .updater = s->output_images, + }, + }; + + RET(ff_vk_add_descriptor_set(ctx, shd, desc_i, 2, 0)); /* set 0 */ + + GLSLF(0, #define FILTER_DIST vec2(%f, %f), dist_x, dist_y); + GLSLD( distort_chroma_kernel ); + GLSLC(0, #define IS_WITHIN(v1, v2) ((v1.x < v2.x) && (v1.y < v2.y)) ); + GLSLC(0, void main() ); + GLSLC(0, { ); + GLSLC(1, ivec2 pos = ivec2(gl_GlobalInvocationID.xy); ); + GLSLF(1, int planes = %i;, planes); + GLSLC(1, for (int i = 0; i < planes; i++) { ); + GLSLC(2, ivec2 size = imageSize(output_img[i]); ); + GLSLC(2, if (!IS_WITHIN(pos, size)) ); + GLSLC(3, continue; ); + GLSLC(2, if ((planes == 1) || (i > 0)) { ); + GLSLC(3, distort_chroma(i, size, pos); ); + GLSLC(2, } else { ); + GLSLC(3, vec2 npos = vec2(pos)/vec2(size); ); + GLSLC(3, vec4 res = texture(input_img[i], npos); ); + GLSLC(3, imageStore(output_img[i], pos, res); ); + GLSLC(2, } ); + GLSLC(1, } ); + GLSLC(0, } ); + + RET(ff_vk_compile_shader(ctx, shd, "main")); + } + + RET(ff_vk_init_pipeline_layout(ctx)); + + /* Execution context */ + RET(av_vk_create_exec_ctx(s->vkctx.device, &s->exec, + s->vkctx.hwctx->queue_family_comp_index)); + + /* The pipeline */ + RET(ff_vk_init_compute_pipeline(ctx)); + + s->initialized = 1; + + return 0; + +fail: + return err; +} + +static int process_frames(AVFilterContext *avctx, AVVkFrame *out, AVVkFrame *in) +{ + int err; + ChromaticAberrationVulkanContext *s = avctx->priv; + int planes = av_pix_fmt_count_planes(s->vkctx.output_format); + + VkCommandBufferBeginInfo cmd_start = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + }; + + VkComponentMapping null_map = { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }; + + for (int i = 0; i < planes; i++) { + RET(ff_vk_create_imageview(avctx, &s->input_images[i].imageView, in, + ff_vk_plane_rep_fmt(s->vkctx.input_format, i), + ff_vk_aspect_flags(s->vkctx.input_format, i), + null_map, NULL)); + + RET(ff_vk_create_imageview(avctx, &s->output_images[i].imageView, out, + ff_vk_plane_rep_fmt(s->vkctx.output_format, i), + ff_vk_aspect_flags(s->vkctx.output_format, i), + null_map, NULL)); + + s->input_images[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL; + s->input_images[i].sampler = s->vkctx.sampler; + + s->output_images[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL; + } + + ff_vk_update_descriptor_set(avctx, 0); + + vkBeginCommandBuffer(s->exec.buf, &cmd_start); + + { + VkImageMemoryBarrier bar[2] = { + { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + .oldLayout = in->layout, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = in->img, + .subresourceRange.aspectMask = ff_vk_aspect_flags(s->vkctx.input_format, -1), + .subresourceRange.levelCount = 1, + .subresourceRange.layerCount = 1, + }, + { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + .oldLayout = out->layout, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = out->img, + .subresourceRange.aspectMask = ff_vk_aspect_flags(s->vkctx.input_format, -1), + .subresourceRange.levelCount = 1, + .subresourceRange.layerCount = 1, + }, + }; + + vkCmdPipelineBarrier(s->exec.buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, + 0, NULL, 0, NULL, 2, bar); + + in->layout = bar[0].newLayout; + in->access = bar[0].dstAccessMask; + + out->layout = bar[1].newLayout; + out->access = bar[1].dstAccessMask; + } + + vkCmdBindPipeline(s->exec.buf, VK_PIPELINE_BIND_POINT_COMPUTE, s->vkctx.pipeline); + vkCmdBindDescriptorSets(s->exec.buf, VK_PIPELINE_BIND_POINT_COMPUTE, s->vkctx.pipeline_layout, 0, s->vkctx.descriptor_sets_num, s->vkctx.desc_set, 0, 0); + vkCmdDispatch(s->exec.buf, + FFALIGN(s->vkctx.output_width, s->vkctx.shaders[0].local_size[0])/s->vkctx.shaders[0].local_size[0], + FFALIGN(s->vkctx.output_height, s->vkctx.shaders[0].local_size[1])/s->vkctx.shaders[0].local_size[1], 1); + + vkEndCommandBuffer(s->exec.buf); + + VkSubmitInfo s_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = 1, + .pCommandBuffers = &s->exec.buf, + }; + + VkResult ret = vkQueueSubmit(s->exec.queue, 1, &s_info, s->exec.fence); + if (ret != VK_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Unable to submit command buffer: %s\n", + av_vk_ret2str(ret)); + return AVERROR_EXTERNAL; + } else { + vkWaitForFences(s->vkctx.hwctx->act_dev, 1, &s->exec.fence, VK_TRUE, UINT64_MAX); + vkResetFences(s->vkctx.hwctx->act_dev, 1, &s->exec.fence); + } + +fail: + + for (int i = 0; i < planes; i++) { + ff_vk_destroy_imageview(avctx, s->input_images[i].imageView); + ff_vk_destroy_imageview(avctx, s->output_images[i].imageView); + } + + return err; +} + +static int chromaticaberration_vulkan_filter_frame(AVFilterLink *link, AVFrame *in) +{ + int err; + AVFilterContext *ctx = link->dst; + ChromaticAberrationVulkanContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + + AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + err = AVERROR(ENOMEM); + goto fail; + } + + if (!s->initialized) + RET(init_filter(ctx, in)); + + RET(process_frames(ctx, (AVVkFrame *)out->data[0], + (AVVkFrame *) in->data[0])); + + err = av_frame_copy_props(out, in); + if (err < 0) + goto fail; + + av_frame_free(&in); + + return ff_filter_frame(outlink, out); + +fail: + av_frame_free(&in); + av_frame_free(&out); + return err; +} + +static void chromaticaberration_vulkan_uninit(AVFilterContext *avctx) +{ + ChromaticAberrationVulkanContext *s = avctx->priv; + + av_vk_free_exec_ctx(s->vkctx.device, &s->exec); + av_vk_free_buf(s->vkctx.device, &s->shader_buf); + ff_vk_filter_uninit(avctx); + + s->initialized = 0; +} + +#define OFFSET(x) offsetof(ChromaticAberrationVulkanContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) +static const AVOption chromaticaberration_vulkan_options[] = { + { "dist_x", "Set horizontal distortion amount", OFFSET(dist_x), AV_OPT_TYPE_FLOAT, {.dbl = 0.0f}, 0.0f, 10.0f, .flags = FLAGS }, + { "dist_y", "Set vertical distortion amount", OFFSET(dist_y), AV_OPT_TYPE_FLOAT, {.dbl = 0.0f}, 0.0f, 10.0f, .flags = FLAGS }, + { NULL }, +}; + +AVFILTER_DEFINE_CLASS(chromaticaberration_vulkan); + +static const AVFilterPad chromaticaberration_vulkan_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = &chromaticaberration_vulkan_filter_frame, + .config_props = &ff_vk_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad chromaticaberration_vulkan_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_vk_filter_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_chromaticaberration_vulkan = { + .name = "chromaticaberration_vulkan", + .description = NULL_IF_CONFIG_SMALL("Apply chromaticaberration mask to input video"), + .priv_size = sizeof(ChromaticAberrationVulkanContext), + .init = &ff_vk_filter_init, + .uninit = &chromaticaberration_vulkan_uninit, + .query_formats = &ff_vk_filter_query_formats, + .inputs = chromaticaberration_vulkan_inputs, + .outputs = chromaticaberration_vulkan_outputs, + .priv_class = &chromaticaberration_vulkan_class, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vulkan.c b/libavfilter/vulkan.c index c2e02f5d0a..c4da2ebe4a 100644 --- a/libavfilter/vulkan.c +++ b/libavfilter/vulkan.c @@ -430,7 +430,7 @@ static VkSamplerYcbcrModelConversion conv_primaries(enum AVColorPrimaries color_ return VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; } -int ff_vk_init_sampler(AVFilterContext *avctx, AVFrame *input) +int ff_vk_init_sampler(AVFilterContext *avctx, AVFrame *input, int unnorm_coords) { VkResult ret; VulkanFilterContext *s = avctx->priv; @@ -475,14 +475,15 @@ int ff_vk_init_sampler(AVFilterContext *avctx, AVFrame *input) .pNext = input ? &s->yuv_sampler : NULL, .magFilter = VK_FILTER_LINEAR, .minFilter = VK_FILTER_LINEAR, - .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, + .mipmapMode = unnorm_coords ? VK_SAMPLER_MIPMAP_MODE_NEAREST : + VK_SAMPLER_MIPMAP_MODE_LINEAR, .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, .addressModeV = sampler.addressModeU, .addressModeW = sampler.addressModeU, .anisotropyEnable = VK_FALSE, .compareOp = VK_COMPARE_OP_NEVER, .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, - .unnormalizedCoordinates = 1, + .unnormalizedCoordinates = unnorm_coords, }; ret = vkCreateSampler(s->hwctx->act_dev, &sampler, NULL, &s->sampler); diff --git a/libavfilter/vulkan.h b/libavfilter/vulkan.h index 6e059731b7..a7becf9ae0 100644 --- a/libavfilter/vulkan.h +++ b/libavfilter/vulkan.h @@ -154,7 +154,7 @@ int ff_vk_add_push_constant(AVFilterContext *avctx, int offset, int size, int ff_vk_init_pipeline_layout(AVFilterContext *avctx); /* Create a Vulkan sampler, if input isn't NULL the sampler will convert to RGB */ -int ff_vk_init_sampler(AVFilterContext *avctx, AVFrame *input); +int ff_vk_init_sampler(AVFilterContext *avctx, AVFrame *input, int unnorm_coords); /* Creates a compute pipeline */ int ff_vk_init_compute_pipeline(AVFilterContext *avctx);