History

ffv1enc: add a Vulkan encoder

This commit implements a standard, compliant, version 3 and version 4 FFv1 encoder, entirely in Vulkan. The encoder is written in standard GLSL and requires a Vulkan 1.3 supporting GPU with the BDA extension. The encoder can use any amount of slices, but nominally, should use 32x32 slices (1024 in total) to maximize parallelism. All features are supported, as well as all pixel formats. This includes: - Rice - Range coding with a custom quantization table - PCM encoding CRC calculation is also massively parallelized on the GPU. Encoding of unaligned dimensions on subsampled data requires version 4, or requires oversizing the image to 64-pixel alignment and cropping out the padding via container flags. Performance-wise, this makes 1080p real-time screen capture possible at 60fps on even modest GPUs.

Lynne committed 2 years ago

Commit ed2391d1 parent a6c583517 files · +2905 −0Browse files

Unified · Split

17 files
  1. configure +1 −0
  2. libavcodec/Makefile +1 −0
  3. libavcodec/allcodecs.c +1 −0
  4. libavcodec/ffv1enc_vulkan.c +1604 −0
  5. libavcodec/vulkan/Makefile +8 −0
  6. libavcodec/vulkan/common.comp +170 −0
  7. libavcodec/vulkan/ffv1_common.comp +74 −0
  8. libavcodec/vulkan/ffv1_enc.comp +67 −0
  9. libavcodec/vulkan/ffv1_enc_ac.comp +83 −0
  10. libavcodec/vulkan/ffv1_enc_common.comp +101 −0
  11. libavcodec/vulkan/ffv1_enc_rct.comp +82 −0
  12. libavcodec/vulkan/ffv1_enc_rgb.comp +83 −0
  13. libavcodec/vulkan/ffv1_enc_setup.comp +151 −0
  14. libavcodec/vulkan/ffv1_enc_vlc.comp +112 −0
  15. libavcodec/vulkan/ffv1_reset.comp +55 −0
  16. libavcodec/vulkan/ffv1_vlc.comp +122 −0
  17. libavcodec/vulkan/rangecoder.comp +190 −0
configure+1−0
@@ -2951,6 +2951,7 @@ exr_decoder_deps="zlib" · 2950 unmodified lines
2951exr_encoder_deps="zlib"2951exr_encoder_deps="zlib"
2952ffv1_decoder_select="rangecoder"2952ffv1_decoder_select="rangecoder"
2953ffv1_encoder_select="rangecoder"2953ffv1_encoder_select="rangecoder"
2954ffv1_vulkan_encoder_select="vulkan spirv_compiler"
2954ffvhuff_decoder_select="huffyuv_decoder"2955ffvhuff_decoder_select="huffyuv_decoder"
2955ffvhuff_encoder_select="huffyuv_encoder"2956ffvhuff_encoder_select="huffyuv_encoder"
2956fic_decoder_select="golomb"2957fic_decoder_select="golomb"
libavcodec/Makefile+1−0
@@ -370,6 +370,7 @@ OBJS-$(CONFIG_EXR_ENCODER) += exrenc.o float2half.o · 369 unmodified lines
370OBJS-$(CONFIG_FASTAUDIO_DECODER) += fastaudio.o370OBJS-$(CONFIG_FASTAUDIO_DECODER) += fastaudio.o
371OBJS-$(CONFIG_FFV1_DECODER) += ffv1dec.o ffv1.o371OBJS-$(CONFIG_FFV1_DECODER) += ffv1dec.o ffv1.o
372OBJS-$(CONFIG_FFV1_ENCODER) += ffv1enc.o ffv1.o372OBJS-$(CONFIG_FFV1_ENCODER) += ffv1enc.o ffv1.o
373OBJS-$(CONFIG_FFV1_VULKAN_ENCODER) += ffv1enc.o ffv1.o ffv1enc_vulkan.o
373OBJS-$(CONFIG_FFWAVESYNTH_DECODER) += ffwavesynth.o374OBJS-$(CONFIG_FFWAVESYNTH_DECODER) += ffwavesynth.o
374OBJS-$(CONFIG_FIC_DECODER) += fic.o375OBJS-$(CONFIG_FIC_DECODER) += fic.o
375OBJS-$(CONFIG_FITS_DECODER) += fitsdec.o fits.o376OBJS-$(CONFIG_FITS_DECODER) += fitsdec.o fits.o
libavcodec/allcodecs.c+1−0
@@ -116,6 +116,7 @@ extern const FFCodec ff_escape130_decoder; · 115 unmodified lines
116extern const FFCodec ff_exr_encoder;116extern const FFCodec ff_exr_encoder;
117extern const FFCodec ff_exr_decoder;117extern const FFCodec ff_exr_decoder;
118extern const FFCodec ff_ffv1_encoder;118extern const FFCodec ff_ffv1_encoder;
119extern const FFCodec ff_ffv1_vulkan_encoder;
119extern const FFCodec ff_ffv1_decoder;120extern const FFCodec ff_ffv1_decoder;
120extern const FFCodec ff_ffvhuff_encoder;121extern const FFCodec ff_ffvhuff_encoder;
121extern const FFCodec ff_ffvhuff_decoder;122extern const FFCodec ff_ffvhuff_decoder;
libavcodec/ffv1enc_vulkan.c+1604−0
@@ -0,0 +1,1604 @@
1/*
2 * Copyright (c) 2024 Lynne <dev@lynne.ee>
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include "libavutil/crc.h"
22#include "libavutil/vulkan.h"
23#include "libavutil/vulkan_spirv.h"
24
25#include "avcodec.h"
26#include "internal.h"
27#include "hwconfig.h"
28#include "encode.h"
29#include "libavutil/opt.h"
30#include "codec_internal.h"
31
32#include "ffv1.h"
33#include "ffv1enc.h"
34
35/* Parallel Golomb alignment */
36#define LG_ALIGN_W 32
37#define LG_ALIGN_H 32
38
39typedef struct VulkanEncodeFFv1Context {
40 FFV1Context ctx;
41
42 FFVulkanContext s;
43 FFVkQueueFamilyCtx qf;
44 FFVkExecPool exec_pool;
45
46 FFVulkanShader setup;
47 FFVulkanShader reset;
48 FFVulkanShader rct;
49 FFVulkanShader enc;
50
51 /* Constant read-only buffers */
52 FFVkBuffer quant_buf;
53 FFVkBuffer rangecoder_static_buf;
54 FFVkBuffer crc_tab_buf;
55
56 /* Slice data buffer pool */
57 AVBufferPool *slice_data_pool;
58 AVBufferRef *keyframe_slice_data_ref;
59
60 /* Output data buffer */
61 AVBufferPool *out_data_pool;
62
63 /* Temporary data buffer */
64 AVBufferPool *tmp_data_pool;
65
66 /* Slice results buffer */
67 AVBufferPool *results_data_pool;
68
69 /* Intermediate frame pool */
70 AVBufferRef *intermediate_frames_ref;
71
72 /* Representation mode */
73 enum FFVkShaderRepFormat rep_fmt;
74
75 int num_h_slices;
76 int num_v_slices;
77 int force_pcm;
78
79 int is_rgb;
80 int ppi;
81 int chunks;
82} VulkanEncodeFFv1Context;
83
84extern const char *ff_source_common_comp;
85extern const char *ff_source_rangecoder_comp;
86extern const char *ff_source_ffv1_vlc_comp;
87extern const char *ff_source_ffv1_common_comp;
88extern const char *ff_source_ffv1_reset_comp;
89extern const char *ff_source_ffv1_enc_common_comp;
90extern const char *ff_source_ffv1_enc_rct_comp;
91extern const char *ff_source_ffv1_enc_vlc_comp;
92extern const char *ff_source_ffv1_enc_ac_comp;
93extern const char *ff_source_ffv1_enc_setup_comp;
94extern const char *ff_source_ffv1_enc_comp;
95extern const char *ff_source_ffv1_enc_rgb_comp;
96
97typedef struct FFv1VkRCTParameters {
98 int offset;
99 uint8_t planar_rgb;
100 uint8_t transparency;
101 uint8_t padding[2];
102} FFv1VkRCTParameters;
103
104typedef struct FFv1VkResetParameters {
105 VkDeviceAddress slice_state;
106 uint32_t plane_state_size;
107 uint32_t context_count;
108 uint8_t codec_planes;
109 uint8_t key_frame;
110 uint8_t padding[3];
111} FFv1VkResetParameters;
112
113typedef struct FFv1VkParameters {
114 VkDeviceAddress slice_state;
115 VkDeviceAddress scratch_data;
116 VkDeviceAddress out_data;
117
118 int32_t sar[2];
119 uint32_t chroma_shift[2];
120
121 uint32_t slice_size_max;
122 uint32_t plane_state_size;
123 uint32_t context_count;
124 uint32_t crcref;
125
126 uint8_t bits_per_raw_sample;
127 uint8_t context_model;
128 uint8_t version;
129 uint8_t micro_version;
130 uint8_t force_pcm;
131 uint8_t key_frame;
132 uint8_t planes;
133 uint8_t codec_planes;
134 uint8_t transparency;
135 uint8_t colorspace;
136 uint8_t pic_mode;
137 uint8_t ec;
138 uint8_t ppi;
139 uint8_t chunks;
140 uint8_t padding[2];
141} FFv1VkParameters;
142
143static void add_push_data(FFVulkanShader *shd)
144{
145 GLSLC(0, layout(push_constant, scalar) uniform pushConstants { );
146 GLSLC(1, u8buf slice_state; );
147 GLSLC(1, u8buf scratch_data; );
148 GLSLC(1, u8buf out_data; );
149 GLSLC(0, );
150 GLSLC(1, ivec2 sar; );
151 GLSLC(1, uvec2 chroma_shift; );
152 GLSLC(0, );
153 GLSLC(1, uint slice_size_max; );
154 GLSLC(1, uint plane_state_size; );
155 GLSLC(1, uint context_count; );
156 GLSLC(1, uint32_t crcref; );
157 GLSLC(0, );
158 GLSLC(1, uint8_t bits_per_raw_sample; );
159 GLSLC(1, uint8_t context_model; );
160 GLSLC(1, uint8_t version; );
161 GLSLC(1, uint8_t micro_version; );
162 GLSLC(1, uint8_t force_pcm; );
163 GLSLC(1, uint8_t key_frame; );
164 GLSLC(1, uint8_t planes; );
165 GLSLC(1, uint8_t codec_planes; );
166 GLSLC(1, uint8_t transparency; );
167 GLSLC(1, uint8_t colorspace; );
168 GLSLC(1, uint8_t pic_mode; );
169 GLSLC(1, uint8_t ec; );
170 GLSLC(1, uint8_t ppi; );
171 GLSLC(1, uint8_t chunks; );
172 GLSLC(1, uint8_t padding[2]; );
173 GLSLC(0, }; );
174 ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1VkParameters),
175 VK_SHADER_STAGE_COMPUTE_BIT);
176}
177
178static int run_rct(AVCodecContext *avctx, FFVkExecContext *exec,
179 AVFrame *enc_in, VkImageView *enc_in_views,
180 AVFrame **intermediate_frame, VkImageView *intermediate_views,
181 VkImageMemoryBarrier2 *img_bar, int *nb_img_bar,
182 VkBufferMemoryBarrier2 *buf_bar, int *nb_buf_bar,
183 FFVkBuffer *slice_data_buf, uint32_t slice_data_size)
184{
185 int err;
186 VulkanEncodeFFv1Context *fv = avctx->priv_data;
187 FFV1Context *f = &fv->ctx;
188 FFVulkanFunctions *vk = &fv->s.vkfn;
189 AVHWFramesContext *src_hwfc = (AVHWFramesContext *)enc_in->hw_frames_ctx->data;
190 FFv1VkRCTParameters pd;
191
192 /* Create a temporaty frame */
193 *intermediate_frame = av_frame_alloc();
194 if (!(*intermediate_frame))
195 return AVERROR(ENOMEM);
196
197 RET(av_hwframe_get_buffer(fv->intermediate_frames_ref,
198 *intermediate_frame, 0));
199
200 RET(ff_vk_exec_add_dep_frame(&fv->s, exec, *intermediate_frame,
201 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
202 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
203 RET(ff_vk_create_imageviews(&fv->s, exec, intermediate_views,
204 *intermediate_frame,
205 fv->rep_fmt));
206
207 /* Update descriptors */
208 ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->rct,
209 1, 0, 0,
210 slice_data_buf,
211 0, slice_data_size*f->slice_count,
212 VK_FORMAT_UNDEFINED);
213 ff_vk_shader_update_img_array(&fv->s, exec, &fv->rct,
214 enc_in, enc_in_views,
215 1, 1,
216 VK_IMAGE_LAYOUT_GENERAL,
217 VK_NULL_HANDLE);
218 ff_vk_shader_update_img_array(&fv->s, exec, &fv->rct,
219 *intermediate_frame, intermediate_views,
220 1, 2,
221 VK_IMAGE_LAYOUT_GENERAL,
222 VK_NULL_HANDLE);
223
224 ff_vk_frame_barrier(&fv->s, exec, *intermediate_frame, img_bar, nb_img_bar,
225 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
226 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
227 VK_ACCESS_SHADER_WRITE_BIT,
228 VK_IMAGE_LAYOUT_GENERAL,
229 VK_QUEUE_FAMILY_IGNORED);
230
231 /* Prep the input/output images */
232 vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
233 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
234 .pImageMemoryBarriers = img_bar,
235 .imageMemoryBarrierCount = *nb_img_bar,
236 .pBufferMemoryBarriers = buf_bar,
237 .bufferMemoryBarrierCount = *nb_buf_bar,
238 });
239 *nb_img_bar = 0;
240 if (*nb_buf_bar) {
241 slice_data_buf->stage = buf_bar[0].dstStageMask;
242 slice_data_buf->access = buf_bar[0].dstAccessMask;
243 *nb_buf_bar = 0;
244 }
245
246 /* Run the shader */
247 ff_vk_exec_bind_shader(&fv->s, exec, &fv->rct);
248 pd = (FFv1VkRCTParameters) {
249 .offset = 1 << f->bits_per_raw_sample,
250 .planar_rgb = ff_vk_mt_is_np_rgb(src_hwfc->sw_format) &&
251 (ff_vk_count_images((AVVkFrame *)enc_in->data[0]) > 1),
252 .transparency = f->transparency,
253 };
254 ff_vk_shader_update_push_const(&fv->s, exec, &fv->rct,
255 VK_SHADER_STAGE_COMPUTE_BIT,
256 0, sizeof(pd), &pd);
257
258 vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, 1);
259
260 /* Add a post-dispatch barrier before encoding */
261 ff_vk_frame_barrier(&fv->s, exec, *intermediate_frame, img_bar, nb_img_bar,
262 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
263 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
264 VK_ACCESS_SHADER_READ_BIT,
265 VK_IMAGE_LAYOUT_GENERAL,
266 VK_QUEUE_FAMILY_IGNORED);
267
268fail:
269 return err;
270}
271
272static int vulkan_encode_ffv1_frame(AVCodecContext *avctx, AVPacket *pkt,
273 const AVFrame *pict, int *got_packet)
274{
275 int err;
276 VulkanEncodeFFv1Context *fv = avctx->priv_data;
277 FFV1Context *f = &fv->ctx;
278 FFVulkanFunctions *vk = &fv->s.vkfn;
279 FFVkExecContext *exec;
280
281 FFv1VkParameters pd;
282
283 AVFrame *intermediate_frame = NULL;
284
285 /* Temporary data */
286 size_t tmp_data_size;
287 AVBufferRef *tmp_data_ref;
288 FFVkBuffer *tmp_data_buf;
289
290 /* Slice data */
291 AVBufferRef *slice_data_ref;
292 FFVkBuffer *slice_data_buf;
293 uint32_t plane_state_size;
294 uint32_t slice_state_size;
295 uint32_t slice_data_size;
296
297 /* Output data */
298 size_t maxsize;
299 AVBufferRef *out_data_ref;
300 FFVkBuffer *out_data_buf;
301 uint8_t *buf_p;
302
303 /* Results data */
304 AVBufferRef *results_data_ref;
305 FFVkBuffer *results_data_buf;
306 uint32_t *sc;
307
308 int has_inter = avctx->gop_size > 1;
309 uint32_t context_count = f->context_count[f->context_model];
310
311 VkImageView in_views[AV_NUM_DATA_POINTERS];
312 VkImageView intermediate_views[AV_NUM_DATA_POINTERS];
313
314 AVFrame *enc_in = (AVFrame *)pict;
315 VkImageView *enc_in_views = in_views;
316
317 VkMappedMemoryRange invalidate_data[2];
318 int nb_invalidate_data = 0;
319
320 VkImageMemoryBarrier2 img_bar[37];
321 int nb_img_bar = 0;
322 VkBufferMemoryBarrier2 buf_bar[8];
323 int nb_buf_bar = 0;
324
325 if (!pict)
326 return 0;
327
328 exec = ff_vk_exec_get(&fv->s, &fv->exec_pool);
329 ff_vk_exec_start(&fv->s, exec);
330
331 /* Frame state */
332 f->cur_enc_frame = pict;
333 if (avctx->gop_size == 0 || f->picture_number % avctx->gop_size == 0) {
334 av_buffer_unref(&fv->keyframe_slice_data_ref);
335 f->key_frame = 1;
336 f->gob_count++;
337 } else {
338 f->key_frame = 0;
339 }
340
341 f->max_slice_count = f->num_h_slices * f->num_v_slices;
342 f->slice_count = f->max_slice_count;
343
344 /* Allocate temporary data buffer */
345 tmp_data_size = f->slice_count*CONTEXT_SIZE;
346 err = ff_vk_get_pooled_buffer(&fv->s, &fv->tmp_data_pool,
347 &tmp_data_ref,
348 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
349 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
350 NULL, tmp_data_size,
351 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
352 if (err < 0)
353 return err;
354 tmp_data_buf = (FFVkBuffer *)tmp_data_ref->data;
355
356 /* Allocate slice buffer data */
357 if (f->ac == AC_GOLOMB_RICE)
358 plane_state_size = 8;
359 else
360 plane_state_size = CONTEXT_SIZE;
361
362 plane_state_size *= context_count;
363 slice_state_size = plane_state_size*f->plane_count;
364
365 slice_data_size = 256; /* Overestimation for the SliceContext struct */
366 slice_state_size += slice_data_size;
367 slice_state_size = FFALIGN(slice_state_size, 8);
368
369 slice_data_ref = fv->keyframe_slice_data_ref;
370 if (!slice_data_ref) {
371 /* Allocate slice data buffer */
372 err = ff_vk_get_pooled_buffer(&fv->s, &fv->slice_data_pool,
373 &slice_data_ref,
374 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
375 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
376 NULL, slice_state_size*f->slice_count,
377 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
378 if (err < 0)
379 return err;
380
381 /* Only save it if we're going to use it again */
382 if (has_inter)
383 fv->keyframe_slice_data_ref = slice_data_ref;
384 }
385 slice_data_buf = (FFVkBuffer *)slice_data_ref->data;
386
387 /* Allocate results buffer */
388 err = ff_vk_get_pooled_buffer(&fv->s, &fv->results_data_pool,
389 &results_data_ref,
390 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
391 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
392 NULL, 2*f->slice_count*sizeof(uint32_t),
393 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
394 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
395 if (err < 0)
396 return err;
397 results_data_buf = (FFVkBuffer *)results_data_ref->data;
398
399 /* Output buffer size */
400 maxsize = avctx->width*avctx->height*(1 + f->transparency);
401 if (f->chroma_planes)
402 maxsize += AV_CEIL_RSHIFT(avctx->width, f->chroma_h_shift) *
403 AV_CEIL_RSHIFT(f->height, f->chroma_v_shift)*2;
404 maxsize += f->slice_count * 800;
405 if (f->version > 3) {
406 maxsize *= f->bits_per_raw_sample + 1;
407 } else {
408 maxsize += f->slice_count * 2 * (avctx->width + avctx->height);
409 maxsize *= 8*(2*f->bits_per_raw_sample + 5);
410 }
411 maxsize >>= 3;
412 maxsize += FF_INPUT_BUFFER_MIN_SIZE;
413
414 if (maxsize > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE - 32) {
415 av_log(avctx, AV_LOG_WARNING, "Cannot allocate worst case packet size, "
416 "the encoding could fail\n");
417 maxsize = INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE - 32;
418 }
419
420 /* Allocate output buffer */
421 err = ff_vk_get_pooled_buffer(&fv->s, &fv->out_data_pool,
422 &out_data_ref,
423 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
424 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
425 NULL, maxsize,
426 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
427 VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
428 if (err < 0)
429 return err;
430
431 out_data_buf = (FFVkBuffer *)out_data_ref->data;
432 pkt->data = out_data_buf->mapped_mem;
433 pkt->size = out_data_buf->size;
434 pkt->buf = out_data_ref;
435
436 /* Add dependencies */
437 ff_vk_exec_add_dep_buf(&fv->s, exec, &tmp_data_ref, 1, 0);
438 ff_vk_exec_add_dep_buf(&fv->s, exec, &results_data_ref, 1, 0);
439 ff_vk_exec_add_dep_buf(&fv->s, exec, &slice_data_ref, 1, has_inter);
440 ff_vk_exec_add_dep_buf(&fv->s, exec, &out_data_ref, 1, 1);
441 RET(ff_vk_exec_add_dep_frame(&fv->s, exec, enc_in,
442 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
443 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT));
444
445 RET(ff_vk_create_imageviews(&fv->s, exec, enc_in_views, enc_in,
446 fv->rep_fmt));
447 ff_vk_frame_barrier(&fv->s, exec, enc_in, img_bar, &nb_img_bar,
448 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
449 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
450 VK_ACCESS_SHADER_READ_BIT,
451 VK_IMAGE_LAYOUT_GENERAL,
452 VK_QUEUE_FAMILY_IGNORED);
453
454 /* Setup shader needs the original input */
455 ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->setup,
456 1, 0, 0,
457 slice_data_buf,
458 0, slice_data_size*f->slice_count,
459 VK_FORMAT_UNDEFINED);
460 ff_vk_shader_update_img_array(&fv->s, exec, &fv->setup,
461 enc_in, enc_in_views,
462 1, 1,
463 VK_IMAGE_LAYOUT_GENERAL,
464 VK_NULL_HANDLE);
465
466 /* Add a buffer barrier between previous and current frame */
467 if (!f->key_frame) {
468 buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) {
469 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
470 .srcStageMask = slice_data_buf->stage,
471 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
472 .srcAccessMask = slice_data_buf->access,
473 .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT |
474 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
475 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
476 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
477 .buffer = slice_data_buf->buf,
478 .size = VK_WHOLE_SIZE,
479 .offset = 0,
480 };
481 }
482
483 vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
484 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
485 .pImageMemoryBarriers = img_bar,
486 .imageMemoryBarrierCount = nb_img_bar,
487 .pBufferMemoryBarriers = buf_bar,
488 .bufferMemoryBarrierCount = nb_buf_bar,
489 });
490 nb_img_bar = 0;
491 if (nb_buf_bar) {
492 slice_data_buf->stage = buf_bar[0].dstStageMask;
493 slice_data_buf->access = buf_bar[0].dstAccessMask;
494 nb_buf_bar = 0;
495 }
496
497 /* Run setup shader */
498 ff_vk_exec_bind_shader(&fv->s, exec, &fv->setup);
499 pd = (FFv1VkParameters) {
500 .slice_state = slice_data_buf->address + f->slice_count*256,
501 .scratch_data = tmp_data_buf->address,
502 .out_data = out_data_buf->address,
503 .slice_size_max = out_data_buf->size / f->slice_count,
504 .bits_per_raw_sample = f->bits_per_raw_sample,
505 .sar[0] = pict->sample_aspect_ratio.num,
506 .sar[1] = pict->sample_aspect_ratio.den,
507 .chroma_shift[0] = f->chroma_h_shift,
508 .chroma_shift[1] = f->chroma_v_shift,
509 .plane_state_size = plane_state_size,
510 .context_count = context_count,
511 .crcref = f->crcref,
512 .context_model = fv->ctx.context_model,
513 .version = f->version,
514 .micro_version = f->micro_version,
515 .force_pcm = fv->force_pcm,
516 .key_frame = f->key_frame,
517 .planes = av_pix_fmt_count_planes(avctx->sw_pix_fmt),
518 .codec_planes = f->plane_count,
519 .transparency = f->transparency,
520 .colorspace = f->colorspace,
521 .pic_mode = !(pict->flags & AV_FRAME_FLAG_INTERLACED) ? 3 :
522 !(pict->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? 2 : 1,
523 .ec = f->ec,
524 .ppi = fv->ppi,
525 .chunks = fv->chunks,
526 };
527 ff_vk_shader_update_push_const(&fv->s, exec, &fv->setup,
528 VK_SHADER_STAGE_COMPUTE_BIT,
529 0, sizeof(pd), &pd);
530 vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, 1);
531
532 /* Setup shader modified the slice data buffer */
533 buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) {
534 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
535 .srcStageMask = slice_data_buf->stage,
536 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
537 .srcAccessMask = slice_data_buf->access,
538 .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT |
539 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
540 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
541 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
542 .buffer = slice_data_buf->buf,
543 .size = slice_data_size*f->slice_count,
544 .offset = 0,
545 };
546
547 if (f->key_frame || f->version > 3) {
548 FFv1VkResetParameters pd_reset;
549
550 ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->reset,
551 1, 0, 0,
552 slice_data_buf,
553 0, slice_data_size*f->slice_count,
554 VK_FORMAT_UNDEFINED);
555
556 /* Run setup shader */
557 ff_vk_exec_bind_shader(&fv->s, exec, &fv->reset);
558 pd_reset = (FFv1VkResetParameters) {
559 .slice_state = slice_data_buf->address + f->slice_count*256,
560 .plane_state_size = plane_state_size,
561 .context_count = context_count,
562 .codec_planes = f->plane_count,
563 .key_frame = f->key_frame,
564 };
565 ff_vk_shader_update_push_const(&fv->s, exec, &fv->reset,
566 VK_SHADER_STAGE_COMPUTE_BIT,
567 0, sizeof(pd_reset), &pd_reset);
568
569 /* Sync between setup and reset shaders */
570 vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
571 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
572 .pBufferMemoryBarriers = buf_bar,
573 .bufferMemoryBarrierCount = nb_buf_bar,
574 });
575 slice_data_buf->stage = buf_bar[0].dstStageMask;
576 slice_data_buf->access = buf_bar[0].dstAccessMask;
577 nb_buf_bar = 0;
578
579 vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices,
580 f->plane_count);
581 }
582
583 /* Run RCT shader */
584 if (fv->is_rgb) {
585 RET(run_rct(avctx, exec,
586 enc_in, enc_in_views,
587 &intermediate_frame, intermediate_views,
588 img_bar, &nb_img_bar, buf_bar, &nb_buf_bar,
589 slice_data_buf, slice_data_size));
590
591 /* Use the new frame */
592 enc_in = intermediate_frame;
593 enc_in_views = intermediate_views;
594 }
595
596 /* If the reset shader ran, insert a barrier now. */
597 if (f->key_frame || f->version > 3) {
598 /* Reset shader modified the slice data buffer */
599 buf_bar[nb_buf_bar++] = (VkBufferMemoryBarrier2) {
600 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
601 .srcStageMask = slice_data_buf->stage,
602 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
603 .srcAccessMask = slice_data_buf->access,
604 .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT |
605 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
606 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
607 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
608 .buffer = slice_data_buf->buf,
609 .size = slice_data_buf->size - slice_data_size*f->slice_count,
610 .offset = slice_data_size*f->slice_count,
611 };
612 }
613
614 /* Final barrier before encoding */
615 vk->CmdPipelineBarrier2(exec->buf, &(VkDependencyInfo) {
616 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
617 .pImageMemoryBarriers = img_bar,
618 .imageMemoryBarrierCount = nb_img_bar,
619 .pBufferMemoryBarriers = buf_bar,
620 .bufferMemoryBarrierCount = nb_buf_bar,
621 });
622 nb_img_bar = 0;
623 if (nb_buf_bar) {
624 slice_data_buf->stage = buf_bar[0].dstStageMask;
625 slice_data_buf->access = buf_bar[0].dstAccessMask;
626 nb_buf_bar = 0;
627 }
628
629 /* Main encode shader */
630 ff_vk_shader_update_desc_buffer(&fv->s, exec, &fv->enc,
631 1, 0, 0,
632 slice_data_buf,
633 0, slice_data_size*f->slice_count,
634 VK_FORMAT_UNDEFINED);
635 ff_vk_shader_update_img_array(&fv->s, exec, &fv->enc,
636 enc_in, enc_in_views,
637 1, 1,
638 VK_IMAGE_LAYOUT_GENERAL,
639 VK_NULL_HANDLE);
640 ff_vk_shader_update_desc_buffer(&fv->s, exec,
641 &fv->enc, 1, 2, 0,
642 results_data_buf,
643 0, results_data_buf->size,
644 VK_FORMAT_UNDEFINED);
645
646 ff_vk_exec_bind_shader(&fv->s, exec, &fv->enc);
647 ff_vk_shader_update_push_const(&fv->s, exec, &fv->enc,
648 VK_SHADER_STAGE_COMPUTE_BIT,
649 0, sizeof(pd), &pd);
650 vk->CmdDispatch(exec->buf, fv->ctx.num_h_slices, fv->ctx.num_v_slices, 1);
651
652 /* Submit */
653 err = ff_vk_exec_submit(&fv->s, exec);
654 if (err < 0)
655 return err;
656
657 /* We need the encoded data immediately */
658 ff_vk_exec_wait(&fv->s, exec);
659 av_frame_free(&intermediate_frame);
660
661 /* Invalidate slice/output data if needed */
662 if (!(results_data_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
663 invalidate_data[nb_invalidate_data++] = (VkMappedMemoryRange) {
664 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
665 .memory = results_data_buf->mem,
666 .offset = 0,
667 .size = VK_WHOLE_SIZE,
668 };
669 if (!(out_data_buf->flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
670 invalidate_data[nb_invalidate_data++] = (VkMappedMemoryRange) {
671 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
672 .memory = out_data_buf->mem,
673 .offset = 0,
674 .size = VK_WHOLE_SIZE,
675 };
676 if (nb_invalidate_data)
677 vk->InvalidateMappedMemoryRanges(fv->s.hwctx->act_dev,
678 nb_invalidate_data, invalidate_data);
679
680 /* First slice is in-place */
681 buf_p = pkt->data;
682 sc = &((uint32_t *)results_data_buf->mapped_mem)[0];
683 av_log(avctx, AV_LOG_VERBOSE, "Slice size = %u (max %i), src offset = %u\n",
684 sc[0], pkt->size / f->slice_count, sc[1]);
685 av_assert0(sc[0] < pkt->size / f->slice_count);
686 av_assert0(sc[0] < (1 << 24));
687 buf_p += sc[0];
688
689 /* We have to copy the rest */
690 for (int i = 1; i < f->slice_count; i++) {
691 uint32_t bytes;
692 uint8_t *bs_start;
693
694 sc = &((uint32_t *)results_data_buf->mapped_mem)[i*2];
695 bytes = sc[0];
696 bs_start = pkt->data + sc[1];
697
698 av_log(avctx, AV_LOG_VERBOSE, "Slice size = %u (max %i), src offset = %u\n",
699 bytes, pkt->size / f->slice_count, sc[1]);
700 av_assert0(bytes < pkt->size / f->slice_count);
701 av_assert0(bytes < (1 << 24));
702
703 memmove(buf_p, bs_start, bytes);
704
705 buf_p += bytes;
706 }
707
708 f->picture_number++;
709 pkt->size = buf_p - pkt->data;
710 pkt->flags |= AV_PKT_FLAG_KEY * f->key_frame;
711 *got_packet = 1;
712
713 av_log(avctx, AV_LOG_VERBOSE, "Total data = %i\n",
714 pkt->size);
715
716fail:
717 /* Frames added as a dep are always referenced, so we only need to
718 * clean this up. */
719 av_frame_free(&intermediate_frame);
720
721 return 0;
722}
723
724static int init_indirect(AVCodecContext *avctx, enum AVPixelFormat sw_format)
725{
726 int err;
727 VulkanEncodeFFv1Context *fv = avctx->priv_data;
728 AVHWFramesContext *frames_ctx;
729 AVVulkanFramesContext *vk_frames;
730
731 fv->intermediate_frames_ref = av_hwframe_ctx_alloc(fv->s.device_ref);
732 if (!fv->intermediate_frames_ref)
733 return AVERROR(ENOMEM);
734
735 frames_ctx = (AVHWFramesContext *)fv->intermediate_frames_ref->data;
736 frames_ctx->format = AV_PIX_FMT_VULKAN;
737 frames_ctx->sw_format = sw_format;
738 frames_ctx->width = FFALIGN(fv->s.frames->width, 32);
739 frames_ctx->height = FFALIGN(fv->s.frames->height, 32);
740
741 vk_frames = frames_ctx->hwctx;
742 vk_frames->tiling = VK_IMAGE_TILING_OPTIMAL;
743 vk_frames->usage = VK_IMAGE_USAGE_STORAGE_BIT;
744 vk_frames->img_flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
745
746 err = av_hwframe_ctx_init(fv->intermediate_frames_ref);
747 if (err < 0) {
748 av_log(avctx, AV_LOG_ERROR, "Unable to initialize frame pool with format %s: %s\n",
749 av_get_pix_fmt_name(sw_format), av_err2str(err));
750 av_buffer_unref(&fv->intermediate_frames_ref);
751 return err;
752 }
753
754 return 0;
755}
756
757static int check_support(AVHWFramesConstraints *constraints,
758 enum AVPixelFormat fmt)
759{
760 for (int i = 0; constraints->valid_sw_formats[i]; i++) {
761 if (constraints->valid_sw_formats[i] == fmt)
762 return 1;
763 }
764 return 0;
765}
766
767static enum AVPixelFormat get_supported_rgb_buffer_fmt(AVCodecContext *avctx)
768{
769 VulkanEncodeFFv1Context *fv = avctx->priv_data;
770
771 enum AVPixelFormat fmt;
772 AVHWFramesConstraints *constraints;
773 constraints = av_hwdevice_get_hwframe_constraints(fv->s.device_ref,
774 NULL);
775
776 /* What we'd like to optimally have */
777 fmt = fv->ctx.use32bit ?
778 (fv->ctx.transparency ? AV_PIX_FMT_RGBA128 : AV_PIX_FMT_RGB96) :
779 (fv->ctx.transparency ? AV_PIX_FMT_RGBA64 : AV_PIX_FMT_RGB48);
780 if (check_support(constraints, fmt))
781 goto end;
782
783 if (fv->ctx.use32bit) {
784 if (check_support(constraints, (fmt = AV_PIX_FMT_RGBA128)))
785 goto end;
786 } else {
787 if (check_support(constraints, (fmt = AV_PIX_FMT_RGBA64)))
788 goto end;
789
790 if (!fv->ctx.transparency &&
791 check_support(constraints, (fmt = AV_PIX_FMT_RGB96)))
792 goto end;
793
794 if (check_support(constraints, (fmt = AV_PIX_FMT_RGBA128)))
795 goto end;
796 }
797
798 fmt = AV_PIX_FMT_NONE;
799
800end:
801 av_hwframe_constraints_free(&constraints);
802 return fmt;
803}
804
805static void define_shared_code(AVCodecContext *avctx, FFVulkanShader *shd)
806{
807 VulkanEncodeFFv1Context *fv = avctx->priv_data;
808 FFV1Context *f = &fv->ctx;
809 int smp_bits = fv->ctx.use32bit ? 32 : 16;
810
811 av_bprintf(&shd->src, "#define CONTEXT_SIZE %i\n" ,CONTEXT_SIZE);
812 av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_MASK 0x%x\n" ,MAX_QUANT_TABLE_MASK);
813
814 if (f->ac == AC_GOLOMB_RICE) {
815 av_bprintf(&shd->src, "#define PB_UNALIGNED\n" );
816 av_bprintf(&shd->src, "#define GOLOMB\n" );
817 }
818
819 GLSLF(0, #define TYPE int%i_t ,smp_bits);
820 GLSLF(0, #define VTYPE2 i%ivec2 ,smp_bits);
821 GLSLF(0, #define VTYPE3 i%ivec3 ,smp_bits);
822 GLSLD(ff_source_common_comp);
823 GLSLD(ff_source_rangecoder_comp);
824
825 if (f->ac == AC_GOLOMB_RICE)
826 GLSLD(ff_source_ffv1_vlc_comp);
827
828 GLSLD(ff_source_ffv1_common_comp);
829}
830
831static int init_setup_shader(AVCodecContext *avctx, FFVkSPIRVCompiler *spv)
832{
833 int err;
834 VulkanEncodeFFv1Context *fv = avctx->priv_data;
835 FFVulkanShader *shd = &fv->setup;
836 FFVulkanDescriptorSetBinding *desc_set;
837
838 uint8_t *spv_data;
839 size_t spv_len;
840 void *spv_opaque = NULL;
841
842 RET(ff_vk_shader_init(&fv->s, shd, "ffv1_setup",
843 VK_SHADER_STAGE_COMPUTE_BIT,
844 (const char *[]) { "GL_EXT_buffer_reference",
845 "GL_EXT_buffer_reference2" }, 2,
846 1, 1, 1,
847 0));
848
849 av_bprintf(&shd->src, "#define MAX_QUANT_TABLES %i\n", MAX_QUANT_TABLES);
850 av_bprintf(&shd->src, "#define MAX_CONTEXT_INPUTS %i\n", MAX_CONTEXT_INPUTS);
851 av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_SIZE %i\n", MAX_QUANT_TABLE_SIZE);
852
853 desc_set = (FFVulkanDescriptorSetBinding []) {
854 {
855 .name = "rangecoder_static_buf",
856 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
857 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
858 .mem_layout = "scalar",
859 .buf_content = "uint8_t zero_one_state[512];",
860 },
861 { /* This descriptor is never used */
862 .name = "quant_buf",
863 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
864 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
865 .mem_layout = "scalar",
866 .buf_content = "int16_t quant_table[MAX_QUANT_TABLES]"
867 "[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE];",
868 },
869 };
870 RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 1, 0));
871
872 define_shared_code(avctx, shd);
873
874 desc_set = (FFVulkanDescriptorSetBinding []) {
875 {
876 .name = "slice_data_buf",
877 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
878 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
879 .buf_content = "SliceContext slice_ctx[1024];",
880 },
881 {
882 .name = "src",
883 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
884 .dimensions = 2,
885 .mem_layout = ff_vk_shader_rep_fmt(fv->s.frames->sw_format,
886 fv->rep_fmt),
887 .elems = av_pix_fmt_count_planes(fv->s.frames->sw_format),
888 .mem_quali = "readonly",
889 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
890 },
891 };
892 RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 0, 0));
893
894 add_push_data(shd);
895
896 GLSLD(ff_source_ffv1_enc_setup_comp);
897
898 RET(spv->compile_shader(&fv->s, spv, shd, &spv_data, &spv_len, "main",
899 &spv_opaque));
900 RET(ff_vk_shader_link(&fv->s, shd, spv_data, spv_len, "main"));
901
902 RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd));
903
904fail:
905 if (spv_opaque)
906 spv->free_shader(spv, &spv_opaque);
907
908 return err;
909}
910
911static int init_reset_shader(AVCodecContext *avctx, FFVkSPIRVCompiler *spv)
912{
913 int err;
914 VulkanEncodeFFv1Context *fv = avctx->priv_data;
915 FFVulkanShader *shd = &fv->reset;
916 FFVulkanDescriptorSetBinding *desc_set;
917
918 uint8_t *spv_data;
919 size_t spv_len;
920 void *spv_opaque = NULL;
921 int wg_dim = FFMIN(fv->s.props.properties.limits.maxComputeWorkGroupSize[0], 1024);
922
923 RET(ff_vk_shader_init(&fv->s, shd, "ffv1_reset",
924 VK_SHADER_STAGE_COMPUTE_BIT,
925 (const char *[]) { "GL_EXT_buffer_reference",
926 "GL_EXT_buffer_reference2" }, 2,
927 wg_dim, 1, 1,
928 0));
929
930 av_bprintf(&shd->src, "#define MAX_QUANT_TABLES %i\n", MAX_QUANT_TABLES);
931 av_bprintf(&shd->src, "#define MAX_CONTEXT_INPUTS %i\n", MAX_CONTEXT_INPUTS);
932 av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_SIZE %i\n", MAX_QUANT_TABLE_SIZE);
933
934 desc_set = (FFVulkanDescriptorSetBinding []) {
935 {
936 .name = "rangecoder_static_buf",
937 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
938 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
939 .mem_layout = "scalar",
940 .buf_content = "uint8_t zero_one_state[512];",
941 },
942 {
943 .name = "quant_buf",
944 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
945 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
946 .mem_layout = "scalar",
947 .buf_content = "int16_t quant_table[MAX_QUANT_TABLES]"
948 "[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE];",
949 },
950 };
951 RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 1, 0));
952
953 define_shared_code(avctx, shd);
954
955 desc_set = (FFVulkanDescriptorSetBinding []) {
956 {
957 .name = "slice_data_buf",
958 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
959 .mem_quali = "readonly",
960 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
961 .buf_content = "SliceContext slice_ctx[1024];",
962 },
963 };
964 RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 1, 0, 0));
965
966 GLSLC(0, layout(push_constant, scalar) uniform pushConstants { );
967 GLSLC(1, u8buf slice_state; );
968 GLSLC(1, uint plane_state_size; );
969 GLSLC(1, uint context_count; );
970 GLSLC(1, uint8_t codec_planes; );
971 GLSLC(1, uint8_t key_frame; );
972 GLSLC(1, uint8_t padding[3]; );
973 GLSLC(0, }; );
974 ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1VkResetParameters),
975 VK_SHADER_STAGE_COMPUTE_BIT);
976
977 GLSLD(ff_source_ffv1_reset_comp);
978
979 RET(spv->compile_shader(&fv->s, spv, shd, &spv_data, &spv_len, "main",
980 &spv_opaque));
981 RET(ff_vk_shader_link(&fv->s, shd, spv_data, spv_len, "main"));
982
983 RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd));
984
985fail:
986 if (spv_opaque)
987 spv->free_shader(spv, &spv_opaque);
988
989 return err;
990}
991
992static int init_rct_shader(AVCodecContext *avctx, FFVkSPIRVCompiler *spv)
993{
994 int err;
995 VulkanEncodeFFv1Context *fv = avctx->priv_data;
996 FFVulkanShader *shd = &fv->rct;
997 FFVulkanDescriptorSetBinding *desc_set;
998
999 uint8_t *spv_data;
1000 size_t spv_len;
1001 void *spv_opaque = NULL;
1002 int wg_count = sqrt(fv->s.props.properties.limits.maxComputeWorkGroupInvocations);
1003
1004 enum AVPixelFormat intermediate_fmt = get_supported_rgb_buffer_fmt(avctx);
1005 if (intermediate_fmt == AV_PIX_FMT_NONE) {
1006 av_log(avctx, AV_LOG_ERROR, "Unable to find a supported compatible "
1007 "pixel format for RCT buffer!\n");
1008 return AVERROR(ENOTSUP);
1009 }
1010
1011 RET(init_indirect(avctx, intermediate_fmt));
1012
1013 RET(ff_vk_shader_init(&fv->s, shd, "ffv1_rct",
1014 VK_SHADER_STAGE_COMPUTE_BIT,
1015 (const char *[]) { "GL_EXT_buffer_reference",
1016 "GL_EXT_buffer_reference2" }, 2,
1017 wg_count, wg_count, 1,
1018 0));
1019
1020 av_bprintf(&shd->src, "#define MAX_QUANT_TABLES %i\n", MAX_QUANT_TABLES);
1021 av_bprintf(&shd->src, "#define MAX_CONTEXT_INPUTS %i\n", MAX_CONTEXT_INPUTS);
1022 av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_SIZE %i\n", MAX_QUANT_TABLE_SIZE);
1023
1024 desc_set = (FFVulkanDescriptorSetBinding []) {
1025 {
1026 .name = "rangecoder_static_buf",
1027 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
1028 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
1029 .mem_layout = "scalar",
1030 .buf_content = "uint8_t zero_one_state[512];",
1031 },
1032 {
1033 .name = "quant_buf",
1034 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
1035 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
1036 .mem_layout = "scalar",
1037 .buf_content = "int16_t quant_table[MAX_QUANT_TABLES]"
1038 "[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE];",
1039 },
1040 };
1041 RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 2, 1, 0));
1042
1043 define_shared_code(avctx, shd);
1044
1045 desc_set = (FFVulkanDescriptorSetBinding []) {
1046 {
1047 .name = "slice_data_buf",
1048 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
1049 .mem_quali = "readonly",
1050 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
1051 .buf_content = "SliceContext slice_ctx[1024];",
1052 },
1053 {
1054 .name = "src",
1055 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
1056 .dimensions = 2,
1057 .mem_layout = ff_vk_shader_rep_fmt(fv->s.frames->sw_format,
1058 fv->rep_fmt),
1059 .elems = av_pix_fmt_count_planes(fv->s.frames->sw_format),
1060 .mem_quali = "readonly",
1061 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
1062 },
1063 {
1064 .name = "dst",
1065 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
1066 .dimensions = 2,
1067 .mem_layout = ff_vk_shader_rep_fmt(intermediate_fmt,
1068 fv->rep_fmt),
1069 .elems = av_pix_fmt_count_planes(intermediate_fmt),
1070 .mem_quali = "writeonly",
1071 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
1072 },
1073 };
1074 RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 3, 0, 0));
1075
1076 GLSLC(0, layout(push_constant, scalar) uniform pushConstants { );
1077 GLSLC(1, int offset; );
1078 GLSLC(1, uint8_t planar_rgb; );
1079 GLSLC(1, uint8_t transparency; );
1080 GLSLC(1, uint8_t padding[2]; );
1081 GLSLC(0, }; );
1082 ff_vk_shader_add_push_const(shd, 0, sizeof(FFv1VkRCTParameters),
1083 VK_SHADER_STAGE_COMPUTE_BIT);
1084
1085 GLSLD(ff_source_ffv1_enc_rct_comp);
1086
1087 RET(spv->compile_shader(&fv->s, spv, shd, &spv_data, &spv_len, "main",
1088 &spv_opaque));
1089 RET(ff_vk_shader_link(&fv->s, shd, spv_data, spv_len, "main"));
1090
1091 RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd));
1092
1093fail:
1094 if (spv_opaque)
1095 spv->free_shader(spv, &spv_opaque);
1096
1097 return err;
1098}
1099
1100static int init_encode_shader(AVCodecContext *avctx, FFVkSPIRVCompiler *spv)
1101{
1102 int err;
1103 VulkanEncodeFFv1Context *fv = avctx->priv_data;
1104 FFV1Context *f = &fv->ctx;
1105 FFVulkanShader *shd = &fv->enc;
1106 FFVulkanDescriptorSetBinding *desc_set;
1107
1108 AVHWFramesContext *frames_ctx = fv->intermediate_frames_ref ?
1109 (AVHWFramesContext *)fv->intermediate_frames_ref->data :
1110 fv->s.frames;
1111
1112 uint8_t *spv_data;
1113 size_t spv_len;
1114 void *spv_opaque = NULL;
1115
1116 RET(ff_vk_shader_init(&fv->s, shd, "ffv1_enc",
1117 VK_SHADER_STAGE_COMPUTE_BIT,
1118 (const char *[]) { "GL_EXT_buffer_reference",
1119 "GL_EXT_buffer_reference2" }, 2,
1120 1, 1, 1,
1121 0));
1122
1123 av_bprintf(&shd->src, "#define MAX_QUANT_TABLES %i\n", MAX_QUANT_TABLES);
1124 av_bprintf(&shd->src, "#define MAX_CONTEXT_INPUTS %i\n", MAX_CONTEXT_INPUTS);
1125 av_bprintf(&shd->src, "#define MAX_QUANT_TABLE_SIZE %i\n", MAX_QUANT_TABLE_SIZE);
1126
1127 desc_set = (FFVulkanDescriptorSetBinding []) {
1128 {
1129 .name = "rangecoder_static_buf",
1130 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
1131 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
1132 .mem_layout = "scalar",
1133 .buf_content = "uint8_t zero_one_state[512];",
1134 },
1135 {
1136 .name = "quant_buf",
1137 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
1138 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
1139 .mem_layout = "scalar",
1140 .buf_content = "int16_t quant_table[MAX_QUANT_TABLES]"
1141 "[MAX_CONTEXT_INPUTS][MAX_QUANT_TABLE_SIZE];",
1142 },
1143 {
1144 .name = "crc_ieee_buf",
1145 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
1146 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
1147 .mem_layout = "scalar",
1148 .buf_content = "uint32_t crc_ieee[256];",
1149 },
1150 };
1151
1152 RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 3, 1, 0));
1153
1154 define_shared_code(avctx, shd);
1155
1156 desc_set = (FFVulkanDescriptorSetBinding []) {
1157 {
1158 .name = "slice_data_buf",
1159 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
1160 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
1161 .buf_content = "SliceContext slice_ctx[1024];",
1162 },
1163 {
1164 .name = "src",
1165 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
1166 .dimensions = 2,
1167 .mem_layout = ff_vk_shader_rep_fmt(frames_ctx->sw_format,
1168 fv->rep_fmt),
1169 .elems = av_pix_fmt_count_planes(frames_ctx->sw_format),
1170 .mem_quali = "readonly",
1171 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
1172 },
1173 {
1174 .name = "results_data_buf",
1175 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
1176 .stages = VK_SHADER_STAGE_COMPUTE_BIT,
1177 .mem_quali = "writeonly",
1178 .buf_content = "uint32_t slice_results[2048];",
1179 },
1180 };
1181 RET(ff_vk_shader_add_descriptor_set(&fv->s, shd, desc_set, 3, 0, 0));
1182
1183 add_push_data(shd);
1184
1185 /* Assemble the shader body */
1186 GLSLD(ff_source_ffv1_enc_common_comp);
1187
1188 if (f->ac == AC_GOLOMB_RICE)
1189 GLSLD(ff_source_ffv1_enc_vlc_comp);
1190 else
1191 GLSLD(ff_source_ffv1_enc_ac_comp);
1192
1193 if (fv->is_rgb)
1194 GLSLD(ff_source_ffv1_enc_rgb_comp);
1195 else
1196 GLSLD(ff_source_ffv1_enc_comp);
1197
1198 RET(spv->compile_shader(&fv->s, spv, shd, &spv_data, &spv_len, "main",
1199 &spv_opaque));
1200 RET(ff_vk_shader_link(&fv->s, shd, spv_data, spv_len, "main"));
1201
1202 RET(ff_vk_shader_register_exec(&fv->s, &fv->exec_pool, shd));
1203
1204fail:
1205 if (spv_opaque)
1206 spv->free_shader(spv, &spv_opaque);
1207
1208 return err;
1209}
1210
1211static int init_state_transition_data(AVCodecContext *avctx)
1212{
1213 int err;
1214 VulkanEncodeFFv1Context *fv = avctx->priv_data;
1215
1216 uint8_t *buf_mapped;
1217 size_t buf_len = 512*sizeof(uint8_t);
1218
1219 RET(ff_vk_create_buf(&fv->s, &fv->rangecoder_static_buf,
1220 buf_len,
1221 NULL, NULL,
1222 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
1223 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
1224 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
1225 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
1226 RET(ff_vk_map_buffer(&fv->s, &fv->rangecoder_static_buf,
1227 &buf_mapped, 0));
1228
1229 for (int i = 1; i < 256; i++) {
1230 buf_mapped[256 + i] = fv->ctx.state_transition[i];
1231 buf_mapped[256 - i] = 256 - (int)fv->ctx.state_transition[i];
1232 }
1233
1234 RET(ff_vk_unmap_buffer(&fv->s, &fv->rangecoder_static_buf, 1));
1235
1236 /* Update descriptors */
1237 RET(ff_vk_shader_update_desc_buffer(&fv->s, &fv->exec_pool.contexts[0],
1238 &fv->setup, 0, 0, 0,
1239 &fv->rangecoder_static_buf,
1240 0, fv->rangecoder_static_buf.size,
1241 VK_FORMAT_UNDEFINED));
1242 RET(ff_vk_shader_update_desc_buffer(&fv->s, &fv->exec_pool.contexts[0],
1243 &fv->enc, 0, 0, 0,
1244 &fv->rangecoder_static_buf,
1245 0, fv->rangecoder_static_buf.size,
1246 VK_FORMAT_UNDEFINED));
1247
1248fail:
1249 return err;
1250}
1251
1252static int init_quant_table_data(AVCodecContext *avctx)
1253{
1254 int err;
1255 VulkanEncodeFFv1Context *fv = avctx->priv_data;
1256
1257 int16_t *buf_mapped;
1258 size_t buf_len = MAX_QUANT_TABLES*
1259 MAX_CONTEXT_INPUTS*
1260 MAX_QUANT_TABLE_SIZE*sizeof(int16_t);
1261
1262 RET(ff_vk_create_buf(&fv->s, &fv->quant_buf,
1263 buf_len,
1264 NULL, NULL,
1265 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
1266 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
1267 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
1268 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
1269 RET(ff_vk_map_buffer(&fv->s, &fv->quant_buf, (void *)&buf_mapped, 0));
1270
1271 memcpy(buf_mapped, fv->ctx.quant_tables,
1272 sizeof(fv->ctx.quant_tables));
1273
1274 RET(ff_vk_unmap_buffer(&fv->s, &fv->quant_buf, 1));
1275 RET(ff_vk_shader_update_desc_buffer(&fv->s, &fv->exec_pool.contexts[0],
1276 &fv->enc, 0, 1, 0,
1277 &fv->quant_buf,
1278 0, fv->quant_buf.size,
1279 VK_FORMAT_UNDEFINED));
1280
1281fail:
1282 return err;
1283}
1284
1285static int init_crc_table_data(AVCodecContext *avctx)
1286{
1287 int err;
1288 VulkanEncodeFFv1Context *fv = avctx->priv_data;
1289
1290 uint32_t *buf_mapped;
1291 size_t buf_len = 256*sizeof(int32_t);
1292
1293 RET(ff_vk_create_buf(&fv->s, &fv->crc_tab_buf,
1294 buf_len,
1295 NULL, NULL,
1296 VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
1297 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
1298 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
1299 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
1300 RET(ff_vk_map_buffer(&fv->s, &fv->crc_tab_buf, (void *)&buf_mapped, 0));
1301
1302 memcpy(buf_mapped, av_crc_get_table(AV_CRC_32_IEEE), buf_len);
1303
1304 RET(ff_vk_unmap_buffer(&fv->s, &fv->crc_tab_buf, 1));
1305 RET(ff_vk_shader_update_desc_buffer(&fv->s, &fv->exec_pool.contexts[0],
1306 &fv->enc, 0, 2, 0,
1307 &fv->crc_tab_buf,
1308 0, fv->crc_tab_buf.size,
1309 VK_FORMAT_UNDEFINED));
1310
1311fail:
1312 return err;
1313}
1314
1315static av_cold int vulkan_encode_ffv1_init(AVCodecContext *avctx)
1316{
1317 int err;
1318 VulkanEncodeFFv1Context *fv = avctx->priv_data;
1319 FFV1Context *f = &fv->ctx;
1320 FFVkSPIRVCompiler *spv;
1321
1322 if ((err = ff_ffv1_common_init(avctx)) < 0)
1323 return err;
1324
1325 if (f->ac == 1)
1326 f->ac = AC_RANGE_CUSTOM_TAB;
1327
1328 err = ff_ffv1_encode_setup_plane_info(avctx, avctx->sw_pix_fmt);
1329 if (err < 0)
1330 return err;
1331
1332 /* Target version 3 by default */
1333 f->version = 3;
1334
1335 err = ff_ffv1_encode_init(avctx);
1336 if (err < 0)
1337 return err;
1338
1339 /* Rice coding did not support high bit depths */
1340 if (f->bits_per_raw_sample > (f->version > 3 ? 16 : 8)) {
1341 if (f->ac == AC_GOLOMB_RICE) {
1342 av_log(avctx, AV_LOG_WARNING, "bits_per_raw_sample > 8, "
1343 "forcing range coder\n");
1344 f->ac = AC_RANGE_CUSTOM_TAB;
1345 }
1346 }
1347
1348 if (f->version < 4 && avctx->gop_size > 1) {
1349 av_log(avctx, AV_LOG_ERROR, "Using inter frames requires version 4 (-level 4)\n");
1350 return AVERROR_INVALIDDATA;
1351 }
1352
1353 if (f->version == 4 && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
1354 av_log(avctx, AV_LOG_ERROR, "Version 4 is experimental and requires -strict -2\n");
1355 return AVERROR_INVALIDDATA;
1356 }
1357
1358 //if (fv->ctx.ac == AC_GOLOMB_RICE) {
1359 if (0) {
1360 int w_a = FFALIGN(avctx->width, LG_ALIGN_W);
1361 int h_a = FFALIGN(avctx->height, LG_ALIGN_H);
1362 int w_sl, h_sl;
1363
1364 /* Pixels per line an invocation handles */
1365 int ppi = 0;
1366 /* Chunk size */
1367 int chunks = 0;
1368
1369 do {
1370 if (ppi < 2)
1371 ppi++;
1372 chunks++;
1373 w_sl = w_a / (LG_ALIGN_W*ppi);
1374 h_sl = h_a / (LG_ALIGN_H*chunks);
1375 } while (w_sl > MAX_SLICES / h_sl);
1376
1377 av_log(avctx, AV_LOG_VERBOSE, "Slice config: %ix%i, %i total\n",
1378 LG_ALIGN_W*ppi, LG_ALIGN_H*chunks, w_sl*h_sl);
1379 av_log(avctx, AV_LOG_VERBOSE, "Horizontal slices: %i (%i pixels per invoc)\n",
1380 w_sl, ppi);
1381 av_log(avctx, AV_LOG_VERBOSE, "Vertical slices: %i (%i chunks)\n",
1382 h_sl, chunks);
1383
1384 f->num_h_slices = w_sl;
1385 f->num_v_slices = h_sl;
1386
1387 fv->ppi = ppi;
1388 fv->chunks = chunks;
1389 } else {
1390 f->num_h_slices = fv->num_h_slices;
1391 f->num_v_slices = fv->num_v_slices;
1392
1393 if (f->num_h_slices <= 0)
1394 f->num_h_slices = 32;
1395 if (f->num_v_slices <= 0)
1396 f->num_v_slices = 32;
1397
1398 f->num_h_slices = FFMIN(f->num_h_slices, avctx->width);
1399 f->num_v_slices = FFMIN(f->num_v_slices, avctx->height);
1400 }
1401
1402 if ((err = ff_ffv1_write_extradata(avctx)) < 0)
1403 return err;
1404
1405 if (f->version < 4) {
1406 if (((f->chroma_h_shift > 0) && (avctx->width % (64 << f->chroma_h_shift))) ||
1407 ((f->chroma_v_shift > 0) && (avctx->height % (64 << f->chroma_v_shift)))) {
1408 av_log(avctx, AV_LOG_ERROR, "Encoding frames with subsampling and unaligned "
1409 "dimensions is only supported in version 4 (-level 4)\n");
1410 return AVERROR_PATCHWELCOME;
1411 }
1412 }
1413
1414 if (fv->force_pcm) {
1415 if (f->version < 4) {
1416 av_log(avctx, AV_LOG_ERROR, "PCM coding only supported by version 4 (-level 4)\n");
1417 return AVERROR_INVALIDDATA;
1418 } else if (f->ac != AC_RANGE_CUSTOM_TAB) {
1419 av_log(avctx, AV_LOG_ERROR, "PCM coding requires range coding\n");
1420 return AVERROR_INVALIDDATA;
1421 }
1422 }
1423
1424 /* Init Vulkan */
1425 err = ff_vk_init(&fv->s, avctx, NULL, avctx->hw_frames_ctx);
1426 if (err < 0)
1427 return err;
1428
1429 err = ff_vk_qf_init(&fv->s, &fv->qf, VK_QUEUE_COMPUTE_BIT);
1430 if (err < 0) {
1431 av_log(avctx, AV_LOG_ERROR, "Device has no compute queues!\n");
1432 return err;
1433 }
1434
1435 err = ff_vk_exec_pool_init(&fv->s, &fv->qf, &fv->exec_pool,
1436 fv->qf.nb_queues*4,
1437 0, 0, 0, NULL);
1438 if (err < 0)
1439 return err;
1440
1441 spv = ff_vk_spirv_init();
1442 if (!spv) {
1443 av_log(avctx, AV_LOG_ERROR, "Unable to initialize SPIR-V compiler!\n");
1444 return AVERROR_EXTERNAL;
1445 }
1446
1447 /* Detect the special RGB coding mode */
1448 fv->is_rgb = !(f->colorspace == 0 && avctx->sw_pix_fmt != AV_PIX_FMT_YA8) &&
1449 !(avctx->sw_pix_fmt == AV_PIX_FMT_YA8);
1450
1451 /* bits_per_raw_sample use regular unsigned representation,
1452 * but in higher bit depths, the data is casted to int16_t */
1453 fv->rep_fmt = FF_VK_REP_UINT;
1454 if (!fv->is_rgb && f->bits_per_raw_sample > 8)
1455 fv->rep_fmt = FF_VK_REP_INT;
1456
1457 /* Init setup shader */
1458 err = init_setup_shader(avctx, spv);
1459 if (err < 0) {
1460 spv->uninit(&spv);
1461 return err;
1462 }
1463
1464 /* Init reset shader */
1465 err = init_reset_shader(avctx, spv);
1466 if (err < 0) {
1467 spv->uninit(&spv);
1468 return err;
1469 }
1470
1471 /* Init RCT shader */
1472 if (fv->is_rgb) {
1473 err = init_rct_shader(avctx, spv);
1474 if (err < 0) {
1475 spv->uninit(&spv);
1476 return err;
1477 }
1478 }
1479
1480 /* Encode shader */
1481 err = init_encode_shader(avctx, spv);
1482 if (err < 0) {
1483 spv->uninit(&spv);
1484 return err;
1485 }
1486
1487 spv->uninit(&spv);
1488
1489 /* Range coder data */
1490 err = init_state_transition_data(avctx);
1491 if (err < 0)
1492 return err;
1493
1494 /* Quantization table data */
1495 err = init_quant_table_data(avctx);
1496 if (err < 0)
1497 return err;
1498
1499 /* CRC table buffer */
1500 err = init_crc_table_data(avctx);
1501 if (err < 0)
1502 return err;
1503
1504 return 0;
1505}
1506
1507static av_cold int vulkan_encode_ffv1_close(AVCodecContext *avctx)
1508{
1509 VulkanEncodeFFv1Context *fv = avctx->priv_data;
1510
1511 ff_vk_exec_pool_free(&fv->s, &fv->exec_pool);
1512
1513 ff_vk_shader_free(&fv->s, &fv->enc);
1514 ff_vk_shader_free(&fv->s, &fv->rct);
1515 ff_vk_shader_free(&fv->s, &fv->reset);
1516 ff_vk_shader_free(&fv->s, &fv->setup);
1517
1518 av_buffer_unref(&fv->intermediate_frames_ref);
1519
1520 av_buffer_pool_uninit(&fv->results_data_pool);
1521
1522 av_buffer_pool_uninit(&fv->out_data_pool);
1523 av_buffer_pool_uninit(&fv->tmp_data_pool);
1524
1525 av_buffer_unref(&fv->keyframe_slice_data_ref);
1526 av_buffer_pool_uninit(&fv->slice_data_pool);
1527
1528 ff_vk_free_buf(&fv->s, &fv->quant_buf);
1529 ff_vk_free_buf(&fv->s, &fv->rangecoder_static_buf);
1530 ff_vk_free_buf(&fv->s, &fv->crc_tab_buf);
1531
1532 ff_vk_uninit(&fv->s);
1533
1534 return 0;
1535}
1536
1537#define OFFSET(x) offsetof(VulkanEncodeFFv1Context, x)
1538#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
1539static const AVOption vulkan_encode_ffv1_options[] = {
1540 { "slicecrc", "Protect slices with CRCs", OFFSET(ctx.ec), AV_OPT_TYPE_BOOL,
1541 { .i64 = -1 }, -1, 1, VE },
1542 { "context", "Context model", OFFSET(ctx.context_model), AV_OPT_TYPE_INT,
1543 { .i64 = 0 }, 0, 1, VE },
1544 { "coder", "Coder type", OFFSET(ctx.ac), AV_OPT_TYPE_INT,
1545 { .i64 = AC_RANGE_CUSTOM_TAB }, -2, 2, VE, .unit = "coder" },
1546 { "rice", "Golomb rice", 0, AV_OPT_TYPE_CONST,
1547 { .i64 = AC_GOLOMB_RICE }, INT_MIN, INT_MAX, VE, .unit = "coder" },
1548 { "range_tab", "Range with custom table", 0, AV_OPT_TYPE_CONST,
1549 { .i64 = AC_RANGE_CUSTOM_TAB }, INT_MIN, INT_MAX, VE, .unit = "coder" },
1550 { "qtable", "Quantization table", OFFSET(ctx.qtable), AV_OPT_TYPE_INT,
1551 { .i64 = -1 }, -1, 2, VE },
1552
1553 { "slices_h", "Number of horizontal slices", OFFSET(num_h_slices), AV_OPT_TYPE_INT,
1554 { .i64 = -1 }, -1, 32, VE },
1555 { "slices_v", "Number of vertical slices", OFFSET(num_v_slices), AV_OPT_TYPE_INT,
1556 { .i64 = -1 }, -1, 32, VE },
1557
1558 { "force_pcm", "Code all slices with no prediction", OFFSET(force_pcm), AV_OPT_TYPE_BOOL,
1559 { .i64 = 0 }, 0, 1, VE },
1560
1561 { NULL }
1562};
1563
1564static const FFCodecDefault vulkan_encode_ffv1_defaults[] = {
1565 { "g", "1" },
1566 { NULL },
1567};
1568
1569static const AVClass vulkan_encode_ffv1_class = {
1570 .class_name = "ffv1_vulkan",
1571 .item_name = av_default_item_name,
1572 .option = vulkan_encode_ffv1_options,
1573 .version = LIBAVUTIL_VERSION_INT,
1574};
1575
1576const AVCodecHWConfigInternal *const vulkan_encode_ffv1_hw_configs[] = {
1577 HW_CONFIG_ENCODER_FRAMES(VULKAN, VULKAN),
1578 NULL,
1579};
1580
1581const FFCodec ff_ffv1_vulkan_encoder = {
1582 .p.name = "ffv1_vulkan",
1583 CODEC_LONG_NAME("FFmpeg video codec #1 (Vulkan)"),
1584 .p.type = AVMEDIA_TYPE_VIDEO,
1585 .p.id = AV_CODEC_ID_FFV1,
1586 .priv_data_size = sizeof(VulkanEncodeFFv1Context),
1587 .init = &vulkan_encode_ffv1_init,
1588 FF_CODEC_ENCODE_CB(vulkan_encode_ffv1_frame),
1589 .close = &vulkan_encode_ffv1_close,
1590 .p.priv_class = &vulkan_encode_ffv1_class,
1591 .p.capabilities = AV_CODEC_CAP_DELAY |
1592 AV_CODEC_CAP_HARDWARE |
1593 AV_CODEC_CAP_DR1 |
1594 AV_CODEC_CAP_ENCODER_FLUSH |
1595 AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
1596 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_EOF_FLUSH,
1597 .defaults = vulkan_encode_ffv1_defaults,
1598 .p.pix_fmts = (const enum AVPixelFormat[]) {
1599 AV_PIX_FMT_VULKAN,
1600 AV_PIX_FMT_NONE,
1601 },
1602 .hw_configs = vulkan_encode_ffv1_hw_configs,
1603 .p.wrapper_name = "vulkan",
1604};
libavcodec/vulkan/Makefile+8−0
@@ -3,6 +3,14 @@ GEN_CLEANSUFFIXES = *.o *.c *.d · 2 unmodified lines
3clean::3clean::
4 $(RM) $(GEN_CLEANSUFFIXES:%=libavcodec/vulkan/%)4 $(RM) $(GEN_CLEANSUFFIXES:%=libavcodec/vulkan/%)
5 5
6OBJS-$(CONFIG_FFV1_VULKAN_ENCODER) += vulkan/common.o \
7 vulkan/rangecoder.o vulkan/ffv1_vlc.o \
8 vulkan/ffv1_common.o vulkan/ffv1_reset.o \
9 vulkan/ffv1_enc_common.o \
10 vulkan/ffv1_enc_rct.o vulkan/ffv1_enc_setup.o \
11 vulkan/ffv1_enc_vlc.o vulkan/ffv1_enc_ac.o \
12 vulkan/ffv1_enc.o vulkan/ffv1_enc_rgb.o
13
6VULKAN = $(subst $(SRC_PATH)/,,$(wildcard $(SRC_PATH)/libavcodec/vulkan/*.comp))14VULKAN = $(subst $(SRC_PATH)/,,$(wildcard $(SRC_PATH)/libavcodec/vulkan/*.comp))
7.SECONDARY: $(VULKAN:.comp=.c)15.SECONDARY: $(VULKAN:.comp=.c)
8libavcodec/vulkan/%.c: TAG = VULKAN16libavcodec/vulkan/%.c: TAG = VULKAN
libavcodec/vulkan/common.comp+170−0
@@ -0,0 +1,170 @@
1/*
2 * Copyright (c) 2024 Lynne <dev@lynne.ee>
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21layout(buffer_reference, buffer_reference_align = 1) buffer u8buf {
22 uint8_t v;
23};
24
25layout(buffer_reference, buffer_reference_align = 2) buffer u16buf {
26 uint16_t v;
27};
28
29layout(buffer_reference, buffer_reference_align = 4) buffer u32buf {
30 uint32_t v;
31};
32
33layout(buffer_reference, buffer_reference_align = 8) buffer u64buf {
34 uint64_t v;
35};
36
37#define OFFBUF(type, b, l) \
38 type(uint64_t(b) + uint64_t(l))
39
40#define zero_extend(a, p) \
41 ((a) & ((1 << (p)) - 1))
42
43#define sign_extend(val, bits) \
44 bitfieldExtract(val, 0, bits)
45
46#define fold(diff, bits) \
47 sign_extend(diff, bits)
48
49#define mid_pred(a, b, c) \
50 max(min((a), (b)), min(max((a), (b)), (c)))
51
52/* TODO: optimize */
53uint align(uint src, uint a)
54{
55 uint res = src % a;
56 if (res == 0)
57 return src;
58 return src + a - res;
59}
60
61/* TODO: optimize */
62uint64_t align64(uint64_t src, uint64_t a)
63{
64 uint64_t res = src % a;
65 if (res == 0)
66 return src;
67 return src + a - res;
68}
69
70#define reverse4(src) \
71 (pack32(unpack8(uint32_t(src)).wzxy))
72
73uint64_t reverse8(uint64_t src)
74{
75 u32vec2 tmp = unpack32(src);
76 tmp.x = reverse4(tmp.x);
77 tmp.y = reverse4(tmp.y);
78 return pack64(tmp.yx);
79}
80
81#ifdef PB_32
82#define BIT_BUF_TYPE uint32_t
83#define BUF_TYPE u32buf
84#define BUF_REVERSE(src) reverse4(src)
85#define BUF_BITS uint8_t(32)
86#define BUF_BYTES uint8_t(4)
87#define BYTE_EXTRACT(src, byte_off) \
88 (uint8_t(bitfieldExtract((src), ((byte_off) << 3), 8)))
89#else
90#define BIT_BUF_TYPE uint64_t
91#define BUF_TYPE u64buf
92#define BUF_REVERSE(src) reverse8(src)
93#define BUF_BITS uint8_t(64)
94#define BUF_BYTES uint8_t(8)
95#define BYTE_EXTRACT(src, byte_off) \
96 (uint8_t(((src) >> ((byte_off) << 3)) & 0xFF))
97#endif
98
99struct PutBitContext {
100 uint64_t buf_start;
101 uint64_t buf;
102
103 BIT_BUF_TYPE bit_buf;
104 uint8_t bit_left;
105};
106
107void put_bits(inout PutBitContext pb, const uint32_t n, uint32_t value)
108{
109 if (n < pb.bit_left) {
110 pb.bit_buf = (pb.bit_buf << n) | value;
111 pb.bit_left -= uint8_t(n);
112 } else {
113 pb.bit_buf <<= pb.bit_left;
114 pb.bit_buf |= (value >> (n - pb.bit_left));
115
116#ifdef PB_UNALIGNED
117 u8buf bs = u8buf(pb.buf);
118 [[unroll]]
119 for (uint8_t i = uint8_t(0); i < BUF_BYTES; i++)
120 bs[i].v = BYTE_EXTRACT(pb.bit_buf, BUF_BYTES - uint8_t(1) - i);
121#else
122#ifdef DEBUG
123 if ((pb.buf % BUF_BYTES) != 0)
124 debugPrintfEXT("put_bits buffer is not aligned!");
125#endif
126
127 BUF_TYPE bs = BUF_TYPE(pb.buf);
128 bs.v = BUF_REVERSE(pb.bit_buf);
129#endif
130 pb.buf = uint64_t(bs) + BUF_BYTES;
131
132 pb.bit_left += BUF_BITS - uint8_t(n);
133 pb.bit_buf = value;
134 }
135}
136
137uint32_t flush_put_bits(inout PutBitContext pb)
138{
139 /* Align bits to MSBs */
140 if (pb.bit_left < BUF_BITS)
141 pb.bit_buf <<= pb.bit_left;
142
143 if (pb.bit_left < BUF_BITS) {
144 uint to_write = ((BUF_BITS - pb.bit_left) >> 3) + 1;
145
146 u8buf bs = u8buf(pb.buf);
147 for (int i = 0; i < to_write; i++)
148 bs[i].v = BYTE_EXTRACT(pb.bit_buf, BUF_BYTES - uint8_t(1) - i);
149 pb.buf = uint64_t(bs) + BUF_BYTES;
150 }
151
152 pb.bit_left = BUF_BITS;
153 pb.bit_buf = 0x0;
154
155 return uint32_t(pb.buf - pb.buf_start);
156}
157
158void init_put_bits(out PutBitContext pb, u8buf data, uint64_t len)
159{
160 pb.buf_start = uint64_t(data);
161 pb.buf = uint64_t(data);
162
163 pb.bit_buf = 0;
164 pb.bit_left = BUF_BITS;
165}
166
167uint64_t put_bits_count(in PutBitContext pb)
168{
169 return (pb.buf - pb.buf_start)*8 + BUF_BITS - pb.bit_left;
170}
libavcodec/vulkan/ffv1_common.comp+74−0
@@ -0,0 +1,74 @@
1/*
2 * FFv1 codec
3 *
4 * Copyright (c) 2024 Lynne <dev@lynne.ee>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23struct SliceContext {
24 RangeCoder c;
25
26#ifdef GOLOMB
27 PutBitContext pb; /* 8*8 bytes */
28#endif
29
30 ivec2 slice_dim;
31 ivec2 slice_pos;
32 ivec2 slice_rct_coef;
33
34 uint hdr_len; // only used for golomb
35 int slice_coding_mode;
36};
37
38/* -1, { -1, 0 } */
39int predict(int L, ivec2 top)
40{
41 return mid_pred(L, L + top[1] - top[0], top[1]);
42}
43
44/* { -2, -1 }, { -1, 0, 1 }, 0 */
45int get_context(VTYPE2 cur_l, VTYPE3 top_l, TYPE top2, uint8_t quant_table_idx)
46{
47 const int LT = top_l[0]; /* -1 */
48 const int T = top_l[1]; /* 0 */
49 const int RT = top_l[2]; /* 1 */
50 const int L = cur_l[1]; /* -1 */
51
52 int base = quant_table[quant_table_idx][0][(L - LT) & MAX_QUANT_TABLE_MASK] +
53 quant_table[quant_table_idx][1][(LT - T) & MAX_QUANT_TABLE_MASK] +
54 quant_table[quant_table_idx][2][(T - RT) & MAX_QUANT_TABLE_MASK];
55
56 if ((quant_table[quant_table_idx][3][127] == 0) &&
57 (quant_table[quant_table_idx][4][127] == 0))
58 return base;
59
60 const int TT = top2; /* -2 */
61 const int LL = cur_l[0]; /* -2 */
62 return base +
63 quant_table[quant_table_idx][3][(LL - L) & MAX_QUANT_TABLE_MASK] +
64 quant_table[quant_table_idx][4][(TT - T) & MAX_QUANT_TABLE_MASK];
65}
66
67const uint32_t log2_run[41] = {
68 0, 0, 0, 0, 1, 1, 1, 1,
69 2, 2, 2, 2, 3, 3, 3, 3,
70 4, 4, 5, 5, 6, 6, 7, 7,
71 8, 9, 10, 11, 12, 13, 14, 15,
72 16, 17, 18, 19, 20, 21, 22, 23,
73 24,
74};
libavcodec/vulkan/ffv1_enc.comp+67−0
@@ -0,0 +1,67 @@
1/*
2 * FFv1 codec
3 *
4 * Copyright (c) 2024 Lynne <dev@lynne.ee>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23void encode_slice(inout SliceContext sc, const uint slice_idx)
24{
25 int bits = bits_per_raw_sample;
26
27#ifndef GOLOMB
28 if (sc.slice_coding_mode == 1) {
29 for (int p = 0; p < planes; p++) {
30
31 int h = sc.slice_dim.y;
32 if (p > 0 && p < 3)
33 h >>= chroma_shift.y;
34
35 for (int y = 0; y < h; y++)
36 encode_line_pcm(sc, y, p, 0, bits);
37 }
38 } else
39#endif
40 {
41 uint64_t slice_state_off = uint64_t(slice_state) +
42 slice_idx*plane_state_size*codec_planes;
43
44 for (int p = 0; p < planes; p++) {
45 int run_index = 0;
46
47 int h = sc.slice_dim.y;
48 if (p > 0 && p < 3)
49 h >>= chroma_shift.y;
50
51 for (int y = 0; y < h; y++)
52 encode_line(sc, slice_state_off, y, p, 0, bits, run_index);
53
54 /* For the second chroma plane, reuse the first plane's state */
55 if (p != 1)
56 slice_state_off += plane_state_size;
57 }
58 }
59
60 finalize_slice(sc, slice_idx);
61}
62
63void main(void)
64{
65 const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x;
66 encode_slice(slice_ctx[slice_idx], slice_idx);
67}
libavcodec/vulkan/ffv1_enc_ac.comp+83−0
@@ -0,0 +1,83 @@
1/*
2 * Copyright (c) 2024 Lynne <dev@lynne.ee>
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21void put_rac(inout RangeCoder c, uint64_t state, bool bit)
22{
23 put_rac_norenorm(c, state, bit);
24 if (c.range < 0x100)
25 renorm_encoder(c);
26}
27
28/* Note - only handles signed values */
29void put_symbol(inout RangeCoder c, uint64_t state, int v)
30{
31 bool is_nil = (v == 0);
32 put_rac(c, state, is_nil);
33 if (is_nil)
34 return;
35
36 const int a = abs(v);
37 const int e = findMSB(a);
38
39 state += 1;
40 for (int i = 0; i < e; i++)
41 put_rac(c, state + min(i, 9), true);
42 put_rac(c, state + min(e, 9), false);
43
44 state += 21;
45 for (int i = e - 1; i >= 0; i--)
46 put_rac(c, state + min(i, 9), bool(bitfieldExtract(a, i, 1)));
47
48 put_rac(c, state - 11 + min(e, 10), v < 0);
49}
50
51void encode_line_pcm(inout SliceContext sc, int y, int p, int comp,
52 int bits)
53{
54 ivec2 sp = sc.slice_pos;
55 int w = sc.slice_dim.x;
56 if (p > 0 && p < 3) {
57 w >>= chroma_shift.x;
58 sp >>= chroma_shift;
59 }
60
61 for (int x = 0; x < w; x++) {
62 uint v = imageLoad(src[p], (sp + ivec2(x, y)))[comp];
63 for (int i = (bits - 1); i >= 0; i--)
64 put_rac_equi(sc.c, bool(bitfieldExtract(v, i, 1)));
65 }
66}
67
68void encode_line(inout SliceContext sc, uint64_t state,
69 int y, int p, int comp, int bits, const int run_index)
70{
71 ivec2 sp = sc.slice_pos;
72
73 int w = sc.slice_dim.x;
74 if (p > 0 && p < 3) {
75 w >>= chroma_shift.x;
76 sp >>= chroma_shift;
77 }
78
79 for (int x = 0; x < w; x++) {
80 const ivec2 d = get_diff(sp + ivec2(x, y), ivec2(x, y), p, comp, w, bits);
81 put_symbol(sc.c, state + CONTEXT_SIZE*d[0], d[1]);
82 }
83}
libavcodec/vulkan/ffv1_enc_common.comp+101−0
@@ -0,0 +1,101 @@
1/*
2 * FFv1 codec
3 *
4 * Copyright (c) 2024 Lynne <dev@lynne.ee>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23ivec2 get_diff(ivec2 pos, ivec2 off, int p, int comp, int sw, int bits)
24{
25 const ivec2 yoff_border1 = off.x == 0 ? ivec2(1, -1) : ivec2(0, 0);
26 const ivec2 yoff_border2 = off.x == 1 ? ivec2(1, -1) : ivec2(0, 0);
27
28 TYPE top2 = TYPE(0);
29 if (off.y > 1)
30 top2 = TYPE(imageLoad(src[p], pos + ivec2(0, -2))[comp]);
31
32 VTYPE3 top = VTYPE3(TYPE(0),
33 TYPE(0),
34 TYPE(0));
35 if (off.y > 0 && off != ivec2(0, 1))
36 top[0] = TYPE(imageLoad(src[p], pos + ivec2(-1, -1) + yoff_border1)[comp]);
37 if (off.y > 0) {
38 top[1] = TYPE(imageLoad(src[p], pos + ivec2(0, -1))[comp]);
39 top[2] = TYPE(imageLoad(src[p], pos + ivec2(min(1, sw - off.x - 1), -1))[comp]);
40 }
41
42 VTYPE3 cur = VTYPE3(TYPE(0),
43 TYPE(0),
44 imageLoad(src[p], pos)[comp]);
45 if (off.x > 0 && off != ivec2(1, 0))
46 cur[0] = TYPE(imageLoad(src[p], pos + ivec2(-2, 0) + yoff_border2)[comp]);
47 if (off != ivec2(0, 0))
48 cur[1] = TYPE(imageLoad(src[p], pos + ivec2(-1, 0) + yoff_border1)[comp]);
49
50 /* context, diff */
51 ivec2 d = ivec2(get_context(VTYPE2(cur), top, top2, context_model),
52 cur[2] - predict(cur[1], VTYPE2(top)));
53
54 if (d[0] < 0)
55 d = -d;
56
57 d[1] = fold(d[1], bits);
58
59 return d;
60}
61
62void finalize_slice(inout SliceContext sc, const uint slice_idx)
63{
64#ifdef GOLOMB
65 uint32_t enc_len = sc.hdr_len + flush_put_bits(sc.pb);
66#else
67 uint32_t enc_len = rac_terminate(sc.c);
68#endif
69
70 u8buf bs = u8buf(sc.c.bytestream_start);
71
72 /* Append slice length */
73 u8vec4 enc_len_p = unpack8(enc_len);
74 bs[enc_len + 0].v = enc_len_p.z;
75 bs[enc_len + 1].v = enc_len_p.y;
76 bs[enc_len + 2].v = enc_len_p.x;
77 enc_len += 3;
78
79 /* Calculate and write CRC */
80 if (ec != 0) {
81 bs[enc_len].v = uint8_t(0);
82 enc_len++;
83
84 uint32_t crc = crcref;
85 for (int i = 0; i < enc_len; i++)
86 crc = crc_ieee[(crc & 0xFF) ^ uint32_t(bs[i].v)] ^ (crc >> 8);
87
88 if (crcref != 0x00000000)
89 crc ^= 0x8CD88196;
90
91 u8vec4 crc_p = unpack8(crc);
92 bs[enc_len + 0].v = crc_p.x;
93 bs[enc_len + 1].v = crc_p.y;
94 bs[enc_len + 2].v = crc_p.z;
95 bs[enc_len + 3].v = crc_p.w;
96 enc_len += 4;
97 }
98
99 slice_results[slice_idx*2 + 0] = enc_len;
100 slice_results[slice_idx*2 + 1] = uint32_t(uint64_t(bs) - uint64_t(out_data));
101}
libavcodec/vulkan/ffv1_enc_rct.comp+82−0
@@ -0,0 +1,82 @@
1/*
2 * FFv1 codec
3 *
4 * Copyright (c) 2024 Lynne <dev@lynne.ee>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23ivec4 load_components(ivec2 pos)
24{
25 if (planar_rgb == 0)
26 return ivec4(imageLoad(src[0], pos));
27
28 ivec4 pix;
29 for (int i = 0; i < (3 + transparency); i++)
30 pix[i] = int(imageLoad(src[i], pos)[0]);
31
32 /* Swizzle out the difference */
33 if (transparency > 0)
34 return pix.brga;
35 return pix.bgra;
36}
37
38void bypass_sample(ivec2 pos)
39{
40 imageStore(dst[0], pos, load_components(pos));
41}
42
43void bypass_block(in SliceContext sc)
44{
45 ivec2 start = ivec2(gl_LocalInvocationID) + sc.slice_pos;
46 ivec2 end = sc.slice_pos + sc.slice_dim;
47 for (uint y = start.y; y < end.y; y += gl_WorkGroupSize.y)
48 for (uint x = start.x; x < end.x; x += gl_WorkGroupSize.x)
49 bypass_sample(ivec2(x, y));
50}
51
52void transform_sample(ivec2 pos, ivec2 rct_coef)
53{
54 ivec4 pix = load_components(pos);
55 pix.b -= pix.g;
56 pix.r -= pix.g;
57 pix.g += (pix.r*rct_coef.x + pix.b*rct_coef.y) >> 2;
58 pix.b += offset;
59 pix.r += offset;
60 imageStore(dst[0], pos, pix);
61}
62
63void transform_block(in SliceContext sc)
64{
65 const ivec2 rct_coef = sc.slice_rct_coef;
66 const ivec2 start = ivec2(gl_LocalInvocationID) + sc.slice_pos;
67 const ivec2 end = sc.slice_pos + sc.slice_dim;
68
69 for (uint y = start.y; y < end.y; y += gl_WorkGroupSize.y)
70 for (uint x = start.x; x < end.x; x += gl_WorkGroupSize.x)
71 transform_sample(ivec2(x, y), rct_coef);
72}
73
74void main()
75{
76 const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x;
77
78 if (slice_ctx[slice_idx].slice_coding_mode == 1)
79 bypass_block(slice_ctx[slice_idx]);
80 else
81 transform_block(slice_ctx[slice_idx]);
82}
libavcodec/vulkan/ffv1_enc_rgb.comp+83−0
@@ -0,0 +1,83 @@
1/*
2 * FFv1 codec
3 *
4 * Copyright (c) 2024 Lynne <dev@lynne.ee>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23void encode_slice_rgb(inout SliceContext sc, const uint slice_idx)
24{
25 int bits = 9;
26 if (bits != 8 || sc.slice_coding_mode != 0)
27 bits = bits_per_raw_sample + int(sc.slice_coding_mode != 1);
28
29 int run_index = 0;
30
31#ifndef GOLOMB
32 if (sc.slice_coding_mode == 1) {
33 if (transparency == 1) {
34 for (int y = 0; y < sc.slice_dim.y; y++) {
35 encode_line_pcm(sc, y, 0, 1, bits);
36 encode_line_pcm(sc, y, 0, 2, bits);
37 encode_line_pcm(sc, y, 0, 0, bits);
38 encode_line_pcm(sc, y, 0, 3, bits);
39 }
40 } else {
41 for (int y = 0; y < sc.slice_dim.y; y++) {
42 encode_line_pcm(sc, y, 0, 1, bits);
43 encode_line_pcm(sc, y, 0, 2, bits);
44 encode_line_pcm(sc, y, 0, 0, bits);
45 }
46 }
47 } else
48#endif
49 {
50 uint64_t slice_state_off = uint64_t(slice_state) +
51 slice_idx*plane_state_size*codec_planes;
52
53 if (transparency == 1) {
54 for (int y = 0; y < sc.slice_dim.y; y++) {
55 encode_line(sc, slice_state_off + plane_state_size*0,
56 y, 0, 1, bits, run_index);
57 encode_line(sc, slice_state_off + plane_state_size*1,
58 y, 0, 2, bits, run_index);
59 encode_line(sc, slice_state_off + plane_state_size*1,
60 y, 0, 0, bits, run_index);
61 encode_line(sc, slice_state_off + plane_state_size*2,
62 y, 0, 3, bits, run_index);
63 }
64 } else {
65 for (int y = 0; y < sc.slice_dim.y; y++) {
66 encode_line(sc, slice_state_off + plane_state_size*0,
67 y, 0, 1, bits, run_index);
68 encode_line(sc, slice_state_off + plane_state_size*1,
69 y, 0, 2, bits, run_index);
70 encode_line(sc, slice_state_off + plane_state_size*1,
71 y, 0, 0, bits, run_index);
72 }
73 }
74 }
75
76 finalize_slice(sc, slice_idx);
77}
78
79void main(void)
80{
81 const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x;
82 encode_slice_rgb(slice_ctx[slice_idx], slice_idx);
83}
libavcodec/vulkan/ffv1_enc_setup.comp+151−0
@@ -0,0 +1,151 @@
1/*
2 * FFv1 codec
3 *
4 * Copyright (c) 2024 Lynne <dev@lynne.ee>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23uint slice_coord(uint width, uint sx, uint num_h_slices, uint chroma_shift)
24{
25 uint mpw = 1 << chroma_shift;
26 uint awidth = align(width, mpw);
27
28 if ((version < 4) || ((version == 4) && (micro_version < 3)))
29 return width * sx / num_h_slices;
30
31 sx = (2 * awidth * sx + num_h_slices * mpw) / (2 * num_h_slices * mpw) * mpw;
32 if (sx == awidth)
33 sx = width;
34
35 return sx;
36}
37
38void init_slice(out SliceContext sc, const uint slice_idx)
39{
40 /* Set coordinates */
41 uvec2 img_size = imageSize(src[0]);
42 uint sxs = slice_coord(img_size.x, gl_WorkGroupID.x + 0,
43 gl_NumWorkGroups.x, chroma_shift.x);
44 uint sxe = slice_coord(img_size.x, gl_WorkGroupID.x + 1,
45 gl_NumWorkGroups.x, chroma_shift.x);
46 uint sys = slice_coord(img_size.y, gl_WorkGroupID.y + 0,
47 gl_NumWorkGroups.y, chroma_shift.y);
48 uint sye = slice_coord(img_size.y, gl_WorkGroupID.y + 1,
49 gl_NumWorkGroups.y, chroma_shift.y);
50
51 sc.slice_pos = ivec2(sxs, sys);
52 sc.slice_dim = ivec2(sxe - sxs, sye - sys);
53 sc.slice_rct_coef = ivec2(1, 1);
54
55 rac_init(sc.c,
56 OFFBUF(u8buf, out_data, slice_idx * slice_size_max),
57 slice_size_max);
58}
59
60void put_rac_full(inout RangeCoder c, uint64_t state, bool bit)
61{
62 put_rac_norenorm(c, state, bit);
63 if (c.range < 0x100)
64 renorm_encoder_full(c);
65}
66
67void put_symbol_unsigned(inout RangeCoder c, uint64_t state, uint v)
68{
69 bool is_nil = (v == 0);
70 put_rac_full(c, state, is_nil);
71 if (is_nil)
72 return;
73
74 const int e = findMSB(v);
75
76 state += 1;
77 for (int i = 0; i < e; i++)
78 put_rac_full(c, state + min(i, 9), true);
79 put_rac_full(c, state + min(e, 9), false);
80
81 state += 21;
82 for (int i = e - 1; i >= 0; i--)
83 put_rac_full(c, state + min(i, 9), bool(bitfieldExtract(v, i, 1)));
84}
85
86void write_slice_header(inout SliceContext sc, uint64_t state)
87{
88 u8buf sb = u8buf(state);
89
90 [[unroll]]
91 for (int i = 0; i < CONTEXT_SIZE; i++)
92 sb[i].v = uint8_t(128);
93
94 put_symbol_unsigned(sc.c, state, gl_WorkGroupID.x);
95 put_symbol_unsigned(sc.c, state, gl_WorkGroupID.y);
96 put_symbol_unsigned(sc.c, state, 0);
97 put_symbol_unsigned(sc.c, state, 0);
98
99 for (int i = 0; i < codec_planes; i++)
100 put_symbol_unsigned(sc.c, state, context_model);
101
102 put_symbol_unsigned(sc.c, state, pic_mode);
103 put_symbol_unsigned(sc.c, state, sar.x);
104 put_symbol_unsigned(sc.c, state, sar.y);
105
106 if (version >= 4) {
107 put_rac_full(sc.c, state, sc.slice_coding_mode == 1);
108 put_symbol_unsigned(sc.c, state, sc.slice_coding_mode);
109 if (sc.slice_coding_mode != 1 && colorspace == 1) {
110 put_symbol_unsigned(sc.c, state, sc.slice_rct_coef.y);
111 put_symbol_unsigned(sc.c, state, sc.slice_rct_coef.x);
112 }
113 }
114}
115
116void write_frame_header(inout SliceContext sc, uint64_t state)
117{
118 u8buf sb = u8buf(state);
119 sb.v = uint8_t(128);
120 put_rac_full(sc.c, state, bool(key_frame));
121}
122
123#ifdef GOLOMB
124void init_golomb(inout SliceContext sc)
125{
126 sc.hdr_len = rac_terminate(sc.c);
127 init_put_bits(sc.pb,
128 OFFBUF(u8buf, sc.c.bytestream_start, sc.hdr_len),
129 slice_size_max - sc.hdr_len);
130}
131#endif
132
133void main(void)
134{
135 const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x;
136
137 /* Write slice data */
138 uint64_t scratch_state = uint64_t(scratch_data) + slice_idx*CONTEXT_SIZE;
139 u8buf sb = u8buf(scratch_state);
140
141 init_slice(slice_ctx[slice_idx], slice_idx);
142
143 if (slice_idx == 0)
144 write_frame_header(slice_ctx[slice_idx], scratch_state);
145
146 write_slice_header(slice_ctx[slice_idx], scratch_state);
147
148#ifdef GOLOMB
149 init_golomb(slice_ctx[slice_idx]);
150#endif
151}
libavcodec/vulkan/ffv1_enc_vlc.comp+112−0
@@ -0,0 +1,112 @@
1/*
2 * FFv1 codec
3 *
4 * Copyright (c) 2024 Lynne <dev@lynne.ee>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23struct RLEState {
24 int count;
25 int diff;
26 int index;
27 bool mode;
28};
29
30void calc_new_state(inout RLEState state, int context)
31{
32 if (context == 0)
33 state.mode = false;
34
35 if (!state.mode)
36 return;
37
38 if (state.diff > 0) {
39 while (state.count >= (1 << log2_run[state.index])) {
40 state.count -= 1 << log2_run[state.index];
41 state.index++;
42 }
43 if (state.index > 0)
44 state.index--;
45 state.count = 0;
46 state.mode = false;
47 if (state.diff > 0)
48 state.diff--;
49 } else {
50 state.count++;
51 }
52}
53
54void encode_line(inout SliceContext sc, uint64_t state,
55 int y, int p, int comp, int bits, inout int run_index)
56{
57 ivec2 sp = sc.slice_pos;
58
59 int w = sc.slice_dim.x;
60 if (p > 0 && p < 3) {
61 w >>= chroma_shift.x;
62 sp >>= chroma_shift;
63 }
64
65 int run_count = 0;
66 bool run_mode = false;
67
68 for (int x = 0; x < w; x++) {
69 ivec2 d = get_diff(sp + ivec2(x, y), ivec2(x, y), p, comp, w, bits);
70
71 if (d[0] == 0)
72 run_mode = true;
73
74 if (run_mode) {
75 if (d[1] != 0) {
76 /* A very unlikely loop */
77 while (run_count >= 1 << log2_run[run_index]) {
78 run_count -= 1 << log2_run[run_index];
79 run_index++;
80 put_bits(sc.pb, 1, 1);
81 }
82
83 put_bits(sc.pb, 1 + log2_run[run_index], run_count);
84 if (run_index != 0)
85 run_index--;
86 run_count = 0;
87 run_mode = false;
88 if (d[1] > 0)
89 d[1]--;
90 } else {
91 run_count++;
92 }
93 }
94
95 if (!run_mode) {
96 VlcState sb = VlcState(state + VLC_STATE_SIZE*d[0]);
97 Symbol sym = get_vlc_symbol(sb, d[1], bits);
98 put_bits(sc.pb, sym.bits, sym.val);
99 }
100 }
101
102 if (run_mode) {
103 while (run_count >= (1 << log2_run[run_index])) {
104 run_count -= 1 << log2_run[run_index];
105 run_index++;
106 put_bits(sc.pb, 1, 1);
107 }
108
109 if (run_count > 0)
110 put_bits(sc.pb, 1, 1);
111 }
112}
libavcodec/vulkan/ffv1_reset.comp+55−0
@@ -0,0 +1,55 @@
1/*
2 * FFv1 codec
3 *
4 * Copyright (c) 2024 Lynne <dev@lynne.ee>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23void main(void)
24{
25 const uint slice_idx = gl_WorkGroupID.y*gl_NumWorkGroups.x + gl_WorkGroupID.x;
26
27 if (slice_ctx[slice_idx].slice_coding_mode == 0 && key_frame == 0)
28 return;
29
30 uint64_t slice_state_off = uint64_t(slice_state) +
31 slice_idx*plane_state_size*codec_planes;
32
33#ifdef GOLOMB
34 uint64_t start = slice_state_off +
35 (gl_WorkGroupID.z*context_count +
36 gl_LocalInvocationID.x)*VLC_STATE_SIZE;
37 for (uint x = gl_LocalInvocationID.x; x < context_count; x += gl_WorkGroupSize.x) {
38 VlcState sb = VlcState(start);
39 sb.drift = int16_t(0);
40 sb.error_sum = uint16_t(4);
41 sb.bias = int8_t(0);
42 sb.count = uint8_t(1);
43 start += gl_WorkGroupSize.x*VLC_STATE_SIZE;
44 }
45#else
46 uint64_t start = slice_state_off +
47 (gl_WorkGroupID.z*context_count)*CONTEXT_SIZE +
48 (gl_LocalInvocationID.x << 2 /* dwords */); /* Bytes */
49 uint count_total = context_count*(CONTEXT_SIZE /* bytes */ >> 2 /* dwords */);
50 for (uint x = gl_LocalInvocationID.x; x < count_total; x += gl_WorkGroupSize.x) {
51 u32buf(start).v = 0x80808080;
52 start += gl_WorkGroupSize.x*(CONTEXT_SIZE >> 3 /* 1/8th of context */);
53 }
54#endif
55}
libavcodec/vulkan/ffv1_vlc.comp+122−0
@@ -0,0 +1,122 @@
1/*
2 * FFv1 codec
3 *
4 * Copyright (c) 2024 Lynne <dev@lynne.ee>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#define VLC_STATE_SIZE 8
24layout(buffer_reference, buffer_reference_align = VLC_STATE_SIZE) buffer VlcState {
25 uint32_t error_sum;
26 int16_t drift;
27 int8_t bias;
28 uint8_t count;
29};
30
31void update_vlc_state(inout VlcState state, const int v)
32{
33 int drift = state.drift;
34 int count = state.count;
35 int bias = state.bias;
36 state.error_sum += uint16_t(abs(v));
37 drift += v;
38
39 if (count == 128) { // FIXME: variable
40 count >>= 1;
41 drift >>= 1;
42 state.error_sum >>= 1;
43 }
44 count++;
45
46 if (drift <= -count) {
47 bias = max(bias - 1, -128);
48 drift = max(drift + count, -count + 1);
49 } else if (drift > 0) {
50 bias = min(bias + 1, 127);
51 drift = min(drift - count, 0);
52 }
53
54 state.bias = int8_t(bias);
55 state.drift = int16_t(drift);
56 state.count = uint8_t(count);
57}
58
59struct Symbol {
60 uint32_t bits;
61 uint32_t val;
62};
63
64Symbol set_ur_golomb(int i, int k, int limit, int esc_len)
65{
66 int e;
67 Symbol sym;
68
69#ifdef DEBUG
70 if (i < 0)
71 debugPrintfEXT("Error: i is zero!");
72#endif
73
74 e = i >> k;
75 if (e < limit) {
76 sym.bits = e + k + 1;
77 sym.val = (1 << k) + zero_extend(i, k);
78 } else {
79 sym.bits = limit + esc_len;
80 sym.val = i - limit + 1;
81 }
82
83 return sym;
84}
85
86/**
87 * write signed golomb rice code (ffv1).
88 */
89Symbol set_sr_golomb(int i, int k, int limit, int esc_len)
90{
91 int v;
92
93 v = -2 * i - 1;
94 v ^= (v >> 31);
95
96 return set_ur_golomb(v, k, limit, esc_len);
97}
98
99Symbol get_vlc_symbol(inout VlcState state, int v, int bits)
100{
101 int i, k, code;
102 Symbol sym;
103 v = fold(v - int(state.bias), bits);
104
105 i = state.count;
106 k = 0;
107 while (i < state.error_sum) { // FIXME: optimize
108 k++;
109 i += i;
110 }
111
112#ifdef DEBUG
113 if (k > 16)
114 debugPrintfEXT("Error: k > 16!");
115#endif
116
117 code = v ^ ((2 * state.drift + state.count) >> 31);
118
119 update_vlc_state(state, v);
120
121 return set_sr_golomb(code, k, 12, bits);
122}
libavcodec/vulkan/rangecoder.comp+190−0
@@ -0,0 +1,190 @@
1/*
2 * FFv1 codec
3 *
4 * Copyright (c) 2024 Lynne <dev@lynne.ee>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23struct RangeCoder {
24 u8buf bytestream_start;
25 u8buf bytestream;
26
27 uint low;
28 uint16_t range;
29 uint8_t outstanding_count;
30 uint8_t outstanding_byte;
31};
32
33/* Full renorm version that can handle outstanding_byte == 0xFF */
34void renorm_encoder_full(inout RangeCoder c)
35{
36 int bs_cnt = 0;
37
38 if (c.outstanding_byte == 0xFF) {
39 c.outstanding_byte = uint8_t(c.low >> 8);
40 } else if (c.low <= 0xFF00) {
41 c.bytestream[bs_cnt++].v = c.outstanding_byte;
42 uint8_t cnt = c.outstanding_count;
43 for (; cnt > 0; cnt--)
44 c.bytestream[bs_cnt++].v = uint8_t(0xFF);
45 c.outstanding_count = uint8_t(0);
46 c.outstanding_byte = uint8_t(c.low >> 8);
47 } else if (c.low >= 0x10000) {
48 c.bytestream[bs_cnt++].v = c.outstanding_byte + uint8_t(1);
49 uint8_t cnt = c.outstanding_count;
50 for (; cnt > 0; cnt--)
51 c.bytestream[bs_cnt++].v = uint8_t(0x00);
52 c.outstanding_count = uint8_t(0);
53 c.outstanding_byte = uint8_t(bitfieldExtract(c.low, 8, 8));
54 } else {
55 c.outstanding_count++;
56 }
57
58 c.bytestream = OFFBUF(u8buf, c.bytestream, bs_cnt);
59 c.range <<= 8;
60 c.low = bitfieldInsert(0, c.low, 8, 8);
61}
62
63/* Cannot deal with outstanding_byte == -1 in the name of speed */
64void renorm_encoder(inout RangeCoder c)
65{
66 uint8_t oc = c.outstanding_count + uint8_t(1);
67 uint low = c.low;
68
69 c.range <<= 8;
70 c.low = bitfieldInsert(0, low, 8, 8);
71
72 if (low > 0xFF00 && low < 0x10000) {
73 c.outstanding_count = oc;
74 return;
75 }
76
77 u8buf bs = c.bytestream;
78 uint8_t outstanding_byte = c.outstanding_byte;
79
80 c.bytestream = OFFBUF(u8buf, bs, oc);
81 c.outstanding_count = uint8_t(0);
82 c.outstanding_byte = uint8_t(low >> 8);
83
84 uint8_t obs = uint8_t(low > 0xFF00);
85 uint8_t fill = obs - uint8_t(1); /* unsigned underflow */
86
87 bs[0].v = outstanding_byte + obs;
88 for (int i = 1; i < oc; i++)
89 bs[i].v = fill;
90}
91
92void put_rac_norenorm(inout RangeCoder c, uint64_t state, bool bit)
93{
94 u8buf sb = u8buf(state);
95 uint val = uint(sb.v);
96 uint16_t range1 = uint16_t((uint(c.range) * val) >> 8);
97
98#ifdef DEBUG
99 if (val == 0)
100 debugPrintfEXT("Error: state is zero (addr: 0x%lx)", uint64_t(sb));
101 if (range1 >= c.range)
102 debugPrintfEXT("Error: range1 >= c.range");
103 if (range1 <= 0)
104 debugPrintfEXT("Error: range1 <= 0");
105#endif
106
107 uint16_t diff = c.range - range1;
108 if (bit) {
109 c.low += diff;
110 c.range = range1;
111 } else {
112 c.range = diff;
113 }
114
115 sb.v = zero_one_state[(uint(bit) << 8) + val];
116
117#ifdef DEBUG
118 if (sb.v == 0)
119 debugPrintfEXT("Error: inserted zero state from tab %i idx %i", bit, val);
120#endif
121}
122
123/* Equiprobable bit */
124void put_rac_equi(inout RangeCoder c, bool bit)
125{
126 uint16_t range1 = c.range >> 1;
127
128#ifdef DEBUG
129 if (range1 >= c.range)
130 debugPrintfEXT("Error: range1 >= c.range");
131 if (range1 <= 0)
132 debugPrintfEXT("Error: range1 <= 0");
133#endif
134
135 if (bit) {
136 c.low += c.range - range1;
137 c.range = range1;
138 } else {
139 c.range -= range1;
140 }
141
142 if (c.range < 0x100)
143 renorm_encoder(c);
144}
145
146void put_rac_terminate(inout RangeCoder c)
147{
148 uint16_t range1 = uint16_t((uint(c.range) * 129) >> 8);
149
150#ifdef DEBUG
151 if (range1 >= c.range)
152 debugPrintfEXT("Error: range1 >= c.range");
153 if (range1 <= 0)
154 debugPrintfEXT("Error: range1 <= 0");
155#endif
156
157 c.range -= range1;
158 if (c.range < 0x100)
159 renorm_encoder(c);
160}
161
162/* Return the number of bytes written. */
163uint32_t rac_terminate(inout RangeCoder c)
164{
165 put_rac_terminate(c);
166 c.range = uint16_t(0xFF);
167 c.low += 0xFF;
168 renorm_encoder(c);
169 c.range = uint16_t(0xFF);
170 renorm_encoder(c);
171
172#ifdef DEBUG
173 if (c.low != 0)
174 debugPrintfEXT("Error: c.low != 0");
175 if (c.range < 0x100)
176 debugPrintfEXT("Error: range < 0x100");
177#endif
178
179 return uint32_t(uint64_t(c.bytestream) - uint64_t(c.bytestream_start));
180}
181
182void rac_init(out RangeCoder r, u8buf data, uint64_t buf_size)
183{
184 r.bytestream_start = data;
185 r.bytestream = data;
186 r.low = 0;
187 r.range = uint16_t(0xFF00);
188 r.outstanding_count = uint8_t(0);
189 r.outstanding_byte = uint8_t(0xFF);
190}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t