vulkan/prores: use vkCmdClearColorImage

The VK spec forbids using clear commands on YUV images,
so we need to allocate separate per-plane images.
This removes the need for a separate reset shader.
This commit is contained in:
averne
2025-12-06 19:45:18 +01:00
committed by Lynne
parent facc32b0d8
commit c384b1e803
4 changed files with 69 additions and 107 deletions
-1
View File
@@ -19,7 +19,6 @@ OBJS-$(CONFIG_PRORES_RAW_VULKAN_HWACCEL) += vulkan/common.o \
vulkan/prores_raw_idct.o
OBJS-$(CONFIG_PRORES_VULKAN_HWACCEL) += vulkan/common.o \
vulkan/prores_reset.o \
vulkan/prores_vld.o \
vulkan/prores_idct.o
-38
View File
@@ -1,38 +0,0 @@
/*
* 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
*/
void main(void)
{
uvec3 gid = gl_GlobalInvocationID;
#ifndef INTERLACED
ivec2 pos = ivec2(gid);
#else
ivec2 pos = ivec2(gid.x, (gid.y << 1) + bottom_field);
#endif
/* Clear luma plane */
imageStore(dst[0], pos, uvec4(0));
/* Clear chroma plane */
if (gid.x < mb_width << (4 - log2_chroma_w)) {
imageStore(dst[1], pos, uvec4(0));
imageStore(dst[2], pos, uvec4(0));
}
/* Alpha plane doesn't need a clear because it is not sparsely encoded */
}
+21 -7
View File
@@ -1088,7 +1088,6 @@ static void free_profile_data(AVHWFramesContext *hwfc)
int ff_vk_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
{
VkFormat vkfmt = VK_FORMAT_UNDEFINED;
int err, dedicated_dpb;
AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data;
AVVulkanFramesContext *hwfc = frames_ctx->hwctx;
@@ -1107,7 +1106,8 @@ int ff_vk_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
return AVERROR(ENOMEM);
err = vulkan_decode_get_profile(avctx, hw_frames_ctx,
&frames_ctx->sw_format, &vkfmt,
&frames_ctx->sw_format,
&hwfc->format[0],
prof, &dedicated_dpb);
if (err < 0) {
av_free(prof);
@@ -1119,6 +1119,7 @@ int ff_vk_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
hwfc->create_pnext = &prof->profile_list;
} else {
hwfc->format[0] = VK_FORMAT_UNDEFINED;
switch (frames_ctx->sw_format) {
case AV_PIX_FMT_GBRAP16:
/* This should be more efficient for downloading and using */
@@ -1141,6 +1142,20 @@ int ff_vk_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
/* mpv has issues with bgr0 mapping, so just remap it */
frames_ctx->sw_format = AV_PIX_FMT_RGB0;
break;
case AV_PIX_FMT_YUVA422P10: /* ProRes needs to clear the input image, which is not possible on YUV formats */
case AV_PIX_FMT_YUVA444P10:
case AV_PIX_FMT_YUVA422P12:
case AV_PIX_FMT_YUVA444P12:
hwfc->format[3] = VK_FORMAT_R16_UNORM;
/* fallthrough */
case AV_PIX_FMT_YUV422P10:
case AV_PIX_FMT_YUV444P10:
case AV_PIX_FMT_YUV422P12:
case AV_PIX_FMT_YUV444P12:
hwfc->format[0] = VK_FORMAT_R16_UNORM;
hwfc->format[1] = VK_FORMAT_R16_UNORM;
hwfc->format[2] = VK_FORMAT_R16_UNORM;
break;
default:
break;
}
@@ -1151,11 +1166,10 @@ int ff_vk_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx)
frames_ctx->height = FFALIGN(avctx->coded_height, 1 << pdesc->log2_chroma_h);
frames_ctx->format = AV_PIX_FMT_VULKAN;
hwfc->format[0] = vkfmt;
hwfc->tiling = VK_IMAGE_TILING_OPTIMAL;
hwfc->usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT;
hwfc->tiling = VK_IMAGE_TILING_OPTIMAL;
hwfc->usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT;
if (prof) {
FFVulkanDecodeShared *ctx;
+48 -61
View File
@@ -24,7 +24,6 @@
#include "libavutil/vulkan_spirv.h"
extern const char *ff_source_common_comp;
extern const char *ff_source_prores_reset_comp;
extern const char *ff_source_prores_vld_comp;
extern const char *ff_source_prores_idct_comp;
@@ -46,7 +45,6 @@ typedef struct ProresVulkanDecodePicture {
} ProresVulkanDecodePicture;
typedef struct ProresVulkanDecodeContext {
FFVulkanShader reset;
FFVulkanShader vld;
FFVulkanShader idct;
@@ -157,12 +155,14 @@ static int vk_prores_end_frame(AVCodecContext *avctx)
ProresVulkanDecodeContext *pv = ctx->sd_ctx;
ProresVulkanDecodePicture *pp = pr->hwaccel_picture_private;
FFVulkanDecodePicture *vp = &pp->vp;
AVFrame *f = pr->frame;
AVVkFrame *vkf = (AVVkFrame *)f->data[0];
ProresVkParameters pd;
FFVkBuffer *slice_data, *metadata;
VkImageMemoryBarrier2 img_bar[AV_NUM_DATA_POINTERS];
VkBufferMemoryBarrier2 buf_bar[2];
int nb_img_bar = 0, nb_buf_bar = 0, err;
int nb_img_bar = 0, nb_buf_bar = 0, nb_imgs, i, err;
const AVPixFmtDescriptor *pix_desc;
if (!pp->slice_num)
@@ -199,12 +199,11 @@ static int vk_prores_end_frame(AVCodecContext *avctx)
RET(ff_vk_exec_start(&ctx->s, exec));
/* Prepare deps */
RET(ff_vk_exec_add_dep_frame(&ctx->s, exec, pr->frame,
RET(ff_vk_exec_add_dep_frame(&ctx->s, exec, f,
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
RET(ff_vk_exec_mirror_sem_value(&ctx->s, exec, &vp->sem, &vp->sem_value,
pr->frame));
RET(ff_vk_exec_mirror_sem_value(&ctx->s, exec, &vp->sem, &vp->sem_value, f));
/* Transfer ownership to the exec context */
RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &vp->slices_buf, 1, 0));
@@ -212,11 +211,47 @@ static int vk_prores_end_frame(AVCodecContext *avctx)
RET(ff_vk_exec_add_dep_buf(&ctx->s, exec, &pp->metadata_buf, 1, 0));
pp->metadata_buf = NULL;
/* Input barrier */
ff_vk_frame_barrier(&ctx->s, exec, pr->frame, img_bar, &nb_img_bar,
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
vkf->layout[0] = VK_IMAGE_LAYOUT_UNDEFINED;
vkf->access[0] = VK_ACCESS_2_NONE;
nb_imgs = ff_vk_count_images(vkf);
if (pr->first_field) {
/* Input barrier */
ff_vk_frame_barrier(&ctx->s, exec, f, img_bar, &nb_img_bar,
VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_2_CLEAR_BIT,
VK_ACCESS_2_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL,
VK_QUEUE_FAMILY_IGNORED);
vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
.pBufferMemoryBarriers = buf_bar,
.bufferMemoryBarrierCount = nb_buf_bar,
.pImageMemoryBarriers = img_bar,
.imageMemoryBarrierCount = nb_img_bar,
});
nb_img_bar = nb_buf_bar = 0;
/* Clear the input image since the vld shader does sparse writes, except for alpha */
for (i = 0; i < FFMIN(nb_imgs, 3); ++i) {
vk->CmdClearColorImage(exec->buf, vkf->img[i],
VK_IMAGE_LAYOUT_GENERAL,
&((VkClearColorValue) { 0 }),
1, &((VkImageSubresourceRange) {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.levelCount = 1,
.layerCount = 1,
}));
}
}
/* Input barrier, or synchronization between clear and vld shader */
ff_vk_frame_barrier(&ctx->s, exec, f, img_bar, &nb_img_bar,
pr->first_field ? VK_PIPELINE_STAGE_2_CLEAR_BIT : VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL,
VK_QUEUE_FAMILY_IGNORED);
@@ -244,37 +279,6 @@ static int vk_prores_end_frame(AVCodecContext *avctx)
});
nb_img_bar = nb_buf_bar = 0;
/* Reset */
ff_vk_shader_update_img_array(&ctx->s, exec, &pv->reset,
pr->frame, vp->view.out,
0, 0,
VK_IMAGE_LAYOUT_GENERAL,
VK_NULL_HANDLE);
ff_vk_exec_bind_shader(&ctx->s, exec, &pv->reset);
ff_vk_shader_update_push_const(&ctx->s, exec, &pv->reset,
VK_SHADER_STAGE_COMPUTE_BIT,
0, sizeof(pd), &pd);
vk->CmdDispatch(exec->buf, pr->mb_width << 1, pr->mb_height << 1, 1);
/* Input frame barrier after reset */
ff_vk_frame_barrier(&ctx->s, exec, pr->frame, img_bar, &nb_img_bar,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_ACCESS_SHADER_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL,
VK_QUEUE_FAMILY_IGNORED);
vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
.pBufferMemoryBarriers = buf_bar,
.bufferMemoryBarrierCount = nb_buf_bar,
.pImageMemoryBarriers = img_bar,
.imageMemoryBarrierCount = nb_img_bar,
});
nb_img_bar = nb_buf_bar = 0;
/* Entropy decode */
ff_vk_shader_update_desc_buffer(&ctx->s, exec, &pv->vld,
0, 0, 0,
@@ -287,7 +291,7 @@ static int vk_prores_end_frame(AVCodecContext *avctx)
pp->mb_params_sz,
VK_FORMAT_UNDEFINED);
ff_vk_shader_update_img_array(&ctx->s, exec, &pv->vld,
pr->frame, vp->view.out,
f, vp->view.out,
0, 2,
VK_IMAGE_LAYOUT_GENERAL,
VK_NULL_HANDLE);
@@ -301,7 +305,7 @@ static int vk_prores_end_frame(AVCodecContext *avctx)
3 + !!pr->alpha_info);
/* Synchronize vld and idct shaders */
ff_vk_frame_barrier(&ctx->s, exec, pr->frame, img_bar, &nb_img_bar,
ff_vk_frame_barrier(&ctx->s, exec, f, img_bar, &nb_img_bar,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
@@ -339,7 +343,7 @@ static int vk_prores_end_frame(AVCodecContext *avctx)
pp->mb_params_sz,
VK_FORMAT_UNDEFINED);
ff_vk_shader_update_img_array(&ctx->s, exec, &pv->idct,
pr->frame, vp->view.out,
f, vp->view.out,
0, 1,
VK_IMAGE_LAYOUT_GENERAL,
VK_NULL_HANDLE);
@@ -434,7 +438,6 @@ static void vk_decode_prores_uninit(FFVulkanDecodeShared *ctx)
{
ProresVulkanDecodeContext *pv = ctx->sd_ctx;
ff_vk_shader_free(&ctx->s, &pv->reset);
ff_vk_shader_free(&ctx->s, &pv->vld);
ff_vk_shader_free(&ctx->s, &pv->idct);
@@ -478,22 +481,6 @@ static int vk_decode_prores_init(AVCodecContext *avctx)
ctx->sd_ctx_free = vk_decode_prores_uninit;
desc_set = (FFVulkanDescriptorSetBinding []) {
{
.name = "dst",
.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.dimensions = 2,
.mem_layout = ff_vk_shader_rep_fmt(out_frames_ctx->sw_format,
FF_VK_REP_NATIVE),
.mem_quali = "writeonly",
.elems = av_pix_fmt_count_planes(out_frames_ctx->sw_format),
.stages = VK_SHADER_STAGE_COMPUTE_BIT,
},
};
RET(init_shader(avctx, &ctx->s, &ctx->exec_pool, spv, &pv->reset,
"prores_dec_reset", "main", desc_set, 1,
ff_source_prores_reset_comp, 0x080801, pr->frame_type != 0));
desc_set = (FFVulkanDescriptorSetBinding []) {
{
.name = "slice_offsets_buf",