Skip to content

Commit f73f8bc

Browse files
committed
Add support for AMD.
1 parent 6d6015f commit f73f8bc

11 files changed

Lines changed: 743 additions & 407 deletions

File tree

src/encoder/h264/encode.rs

Lines changed: 41 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use super::{H264Encoder, MIN_BITSTREAM_BUFFER_SIZE};
1+
use super::H264Encoder;
22

33
use crate::encoder::gop::{GopFrameType, GopPosition};
4+
use crate::encoder::resources::{record_dpb_barriers, MIN_BITSTREAM_BUFFER_SIZE};
45
use crate::error::{PixelForgeError, Result};
56
use ash::vk;
67
use tracing::debug;
@@ -28,9 +29,9 @@ impl H264Encoder {
2829
// Rate control setup.
2930
let (rc_mode, average_bitrate, max_bitrate, qp) = match self.config.rate_control_mode {
3031
crate::encoder::RateControlMode::Cqp | crate::encoder::RateControlMode::Disabled => (
31-
vk::VideoEncodeRateControlModeFlagsKHR::VBR,
32-
100_000_000, // 100 Mbps
33-
100_000_000,
32+
vk::VideoEncodeRateControlModeFlagsKHR::DISABLED,
33+
0,
34+
0,
3435
self.config.quality_level as i32,
3536
),
3637
crate::encoder::RateControlMode::Cbr => (
@@ -77,32 +78,16 @@ impl H264Encoder {
7778
);
7879
}
7980

80-
// Transition DPB image to video encode DPB layout if needed.
81-
let dpb_barrier = vk::ImageMemoryBarrier::default()
82-
.old_layout(vk::ImageLayout::UNDEFINED)
83-
.new_layout(vk::ImageLayout::VIDEO_ENCODE_DPB_KHR)
84-
.src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
85-
.dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
86-
.image(self.dpb_images[self.current_dpb_slot as usize])
87-
.subresource_range(vk::ImageSubresourceRange {
88-
aspect_mask: vk::ImageAspectFlags::COLOR,
89-
base_mip_level: 0,
90-
level_count: 1,
91-
base_array_layer: 0,
92-
layer_count: 1,
93-
})
94-
.src_access_mask(vk::AccessFlags::empty())
95-
.dst_access_mask(vk::AccessFlags::empty());
96-
81+
// Transition DPB images for encode.
82+
let ref_dpb_slots: Vec<u8> = self.l0_references.iter().map(|r| r.dpb_slot).collect();
9783
unsafe {
98-
self.context.device().cmd_pipeline_barrier(
84+
record_dpb_barriers(
85+
self.context.device(),
9986
self.encode_command_buffer,
100-
vk::PipelineStageFlags::TOP_OF_PIPE,
101-
vk::PipelineStageFlags::BOTTOM_OF_PIPE, // Use BOTTOM_OF_PIPE as VIDEO_ENCODE requires sync2
102-
vk::DependencyFlags::empty(),
103-
&[],
104-
&[],
105-
&[dpb_barrier],
87+
&self.dpb_images,
88+
self.use_layered_dpb,
89+
self.current_dpb_slot,
90+
&ref_dpb_slots,
10691
);
10792
}
10893

@@ -135,7 +120,7 @@ impl H264Encoder {
135120

136121
let slice_qp_delta = match self.config.rate_control_mode {
137122
crate::encoder::RateControlMode::Cqp | crate::encoder::RateControlMode::Disabled => {
138-
((self.config.quality_level as i32) - 26) as i8
123+
(self.config.quality_level as i32 - 26) as i8
139124
}
140125
_ => 0,
141126
};
@@ -150,7 +135,7 @@ impl H264Encoder {
150135
reserved1: 0,
151136
cabac_init_idc:
152137
ash::vk::native::StdVideoH264CabacInitIdc_STD_VIDEO_H264_CABAC_INIT_IDC_0,
153-
disable_deblocking_filter_idc: ash::vk::native::StdVideoH264DisableDeblockingFilterIdc_STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_DISABLED,
138+
disable_deblocking_filter_idc: ash::vk::native::StdVideoH264DisableDeblockingFilterIdc_STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_ENABLED,
154139
pWeightTable: std::ptr::null(),
155140
};
156141

@@ -278,9 +263,9 @@ impl H264Encoder {
278263
};
279264

280265
// Create slice NAL unit entry.
281-
// constant_qp should only be set when rate control is DISABLED
266+
// constant_qp should only be set when rate control is DISABLED.
282267
let constant_qp = if rc_mode == vk::VideoEncodeRateControlModeFlagsKHR::DISABLED {
283-
self.config.quality_level as i32
268+
qp
284269
} else {
285270
0
286271
};
@@ -297,8 +282,8 @@ impl H264Encoder {
297282
let src_picture_resource = vk::VideoPictureResourceInfoKHR::default()
298283
.coded_offset(vk::Offset2D { x: 0, y: 0 })
299284
.coded_extent(vk::Extent2D {
300-
width: self.config.dimensions.width,
301-
height: self.config.dimensions.height,
285+
width: self.aligned_width,
286+
height: self.aligned_height,
302287
})
303288
.base_array_layer(0)
304289
.image_view_binding(self.input_image_view);
@@ -307,8 +292,8 @@ impl H264Encoder {
307292
let setup_picture_resource = vk::VideoPictureResourceInfoKHR::default()
308293
.coded_offset(vk::Offset2D { x: 0, y: 0 })
309294
.coded_extent(vk::Extent2D {
310-
width: self.config.dimensions.width,
311-
height: self.config.dimensions.height,
295+
width: self.aligned_width,
296+
height: self.aligned_height,
312297
})
313298
.base_array_layer(0)
314299
.image_view_binding(self.dpb_image_views[self.current_dpb_slot as usize]);
@@ -333,8 +318,8 @@ impl H264Encoder {
333318
vk::VideoPictureResourceInfoKHR::default()
334319
.coded_offset(vk::Offset2D { x: 0, y: 0 })
335320
.coded_extent(vk::Extent2D {
336-
width: self.config.dimensions.width,
337-
height: self.config.dimensions.height,
321+
width: self.aligned_width,
322+
height: self.aligned_height,
338323
})
339324
.base_array_layer(0)
340325
.image_view_binding(self.dpb_image_views[ref_info.dpb_slot as usize]),
@@ -381,8 +366,8 @@ impl H264Encoder {
381366
let resource = vk::VideoPictureResourceInfoKHR::default()
382367
.coded_offset(vk::Offset2D { x: 0, y: 0 })
383368
.coded_extent(vk::Extent2D {
384-
width: self.config.dimensions.width,
385-
height: self.config.dimensions.height,
369+
width: self.aligned_width,
370+
height: self.aligned_height,
386371
})
387372
.base_array_layer(0)
388373
.image_view_binding(image_view);
@@ -580,25 +565,27 @@ impl H264Encoder {
580565
);
581566
}
582567

583-
// Reset video coding state for the first frame, then set rate control.
568+
// Reset video coding state for the first frame.
569+
// Combine RESET + RATE_CONTROL + QUALITY_LEVEL into a single control command.
570+
// This matches FFmpeg's approach and is required for AMD RADV.
584571
if is_first_frame {
585-
let reset_control_info = vk::VideoCodingControlInfoKHR::default()
586-
.flags(vk::VideoCodingControlFlagsKHR::RESET);
587-
unsafe {
588-
(self.video_queue_fn.fp().cmd_control_video_coding_khr)(
589-
self.encode_command_buffer,
590-
&reset_control_info,
591-
);
592-
}
572+
let mut quality_level_info =
573+
vk::VideoEncodeQualityLevelInfoKHR::default().quality_level(0);
574+
quality_level_info.p_next =
575+
(&mut rc_info as *mut vk::VideoEncodeRateControlInfoKHR).cast();
576+
577+
let mut control_info = vk::VideoCodingControlInfoKHR::default().flags(
578+
vk::VideoCodingControlFlagsKHR::RESET
579+
| vk::VideoCodingControlFlagsKHR::ENCODE_RATE_CONTROL
580+
| vk::VideoCodingControlFlagsKHR::ENCODE_QUALITY_LEVEL,
581+
);
582+
control_info.p_next =
583+
(&mut quality_level_info as *mut vk::VideoEncodeQualityLevelInfoKHR).cast();
593584

594-
// After RESET, set the rate control mode.
595-
let mut rate_control = vk::VideoCodingControlInfoKHR::default()
596-
.flags(vk::VideoCodingControlFlagsKHR::ENCODE_RATE_CONTROL);
597-
rate_control.p_next = (&mut rc_info as *mut vk::VideoEncodeRateControlInfoKHR).cast();
598585
unsafe {
599586
(self.video_queue_fn.fp().cmd_control_video_coding_khr)(
600587
self.encode_command_buffer,
601-
&rate_control,
588+
&control_info,
602589
);
603590
}
604591
}

0 commit comments

Comments
 (0)