Skip to content

Commit

Permalink
move VPP out of JpegDecodeSession
Browse files Browse the repository at this point in the history
  • Loading branch information
SludgePhD committed Mar 8, 2024
1 parent 241a5db commit 9f1cf72
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 47 deletions.
54 changes: 44 additions & 10 deletions examples/jpeg-decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ use std::{num::NonZeroU32, rc::Rc, time::Instant};

use anyhow::bail;
use fev::{
buffer::{Buffer, BufferType},
config::Config,
context::Context,
display::Display,
image::{Image, ImageFormat},
jpeg::{JpegDecodeSession, JpegInfo},
surface::ExportSurfaceFlags,
PixelFormat,
surface::{ExportSurfaceFlags, Surface},
vpp::{ColorProperties, ColorStandardType, ProcPipelineParameterBuffer, SourceRange},
Entrypoint, PixelFormat, Profile,
};
use winit::{
dpi::PhysicalSize,
Expand Down Expand Up @@ -53,24 +57,31 @@ fn main() -> anyhow::Result<()> {

let graphics_context = softbuffer::Context::new(win.clone()).unwrap();
let mut surface = softbuffer::Surface::new(&graphics_context, win.clone()).unwrap();
let PhysicalSize { width, height } = win.inner_size();
log::info!("window size: {width}x{height}");
let s = win.inner_size();
log::info!("window size: {}x{}", s.width, s.height);

let jpeg_info = JpegInfo::new(&jpeg)?;
let (width, height) = (jpeg_info.width(), jpeg_info.height());
surface
.resize(
NonZeroU32::new(info.width.into()).unwrap(),
NonZeroU32::new(info.height.into()).unwrap(),
NonZeroU32::new(width.into()).unwrap(),
NonZeroU32::new(height.into()).unwrap(),
)
.unwrap();

let display = Display::new(win.clone())?;

let jpeg_info = JpegInfo::new(&jpeg)?;
let mut context = JpegDecodeSession::new(&display, jpeg_info.width(), jpeg_info.height())?;
let mut context = JpegDecodeSession::new(&display, width, height)?;
let prime = context
.surface()
.export_prime(ExportSurfaceFlags::SEPARATE_LAYERS | ExportSurfaceFlags::READ)?;
log::debug!("PRIME export: {prime:#?}");

let config = Config::new(&display, Profile::None, Entrypoint::VideoProc)?;
let mut vpp_context = Context::new(&config, width.into(), height.into())?;
let mut vpp_surface =
Surface::with_pixel_format(&display, width.into(), height.into(), PixelFormat::RGBA)?;

let mut image = Image::new(
&display,
ImageFormat::new(PixelFormat::RGBA),
Expand All @@ -80,9 +91,32 @@ fn main() -> anyhow::Result<()> {

log::debug!("<decode>");
let start = Instant::now();
let surf = context.decode_and_convert(&jpeg)?;
let surf = context.decode(&jpeg)?;
log::debug!("</decode> took {:?}", start.elapsed());
surf.copy_to_image(&mut image)?;

// Use VPP to convert the surface to RGBA.
let mut pppbuf = ProcPipelineParameterBuffer::new(surf);

// The input color space is the JPEG color space
let input_props = ColorProperties::new().with_color_range(SourceRange::FULL);
pppbuf.set_input_color_properties(input_props);
pppbuf.set_input_color_standard(ColorStandardType::BT601);
// The output color space is 8-bit non-linear sRGB
let output_props = ColorProperties::new().with_color_range(SourceRange::FULL);
pppbuf.set_output_color_properties(output_props);
pppbuf.set_output_color_standard(ColorStandardType::SRGB);
// NB: not all implementations support converting color standards (eg. Mesa).
// such implementations will typically output an image that is brighter than the reference data.

let mut pppbuf = Buffer::new_param(&vpp_context, BufferType::ProcPipelineParameter, pppbuf)?;

let mut picture = vpp_context.begin_picture(&mut vpp_surface)?;
picture.render_picture(&mut pppbuf)?;
unsafe { picture.end_picture()? }

drop(pppbuf);

vpp_surface.copy_to_image(&mut image)?;
let mapping = image.map()?;

log::debug!("{} byte output", mapping.len());
Expand Down
38 changes: 1 addition & 37 deletions src/jpeg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ use crate::{
error::Error,
raw::{Rectangle, VA_PADDING_LOW, VA_PADDING_MEDIUM},
surface::{RTFormat, Surface},
vpp::{ColorProperties, ColorStandardType, ProcPipelineParameterBuffer, SourceRange},
Entrypoint, PixelFormat, Profile, Result, Rotation, SliceParameterBufferBase,
Entrypoint, Profile, Result, Rotation, SliceParameterBufferBase,
};

use self::parser::{JpegParser, SegmentKind, SofMarker};
Expand Down Expand Up @@ -420,12 +419,8 @@ impl JpegInfo {
pub struct JpegDecodeSession {
width: u32,
height: u32,

jpeg_surface: Surface,
vpp_surface: Surface,

jpeg_context: Context,
vpp_context: Context,
}

impl JpegDecodeSession {
Expand All @@ -444,19 +439,13 @@ impl JpegDecodeSession {

let config = Config::new(&display, Profile::JPEGBaseline, Entrypoint::VLD)?;
let jpeg_context = Context::new(&config, width, height)?;
let config = Config::new(&display, Profile::None, Entrypoint::VideoProc)?;
let vpp_context = Context::new(&config, width, height)?;

let jpeg_surface = Surface::new(&display, width, height, RTFormat::YUV420)?;
let vpp_surface = Surface::with_pixel_format(&display, width, height, PixelFormat::RGBA)?;

Ok(Self {
width,
height,
jpeg_surface,
vpp_surface,
jpeg_context,
vpp_context,
})
}

Expand Down Expand Up @@ -614,29 +603,4 @@ impl JpegDecodeSession {

Ok(&mut self.jpeg_surface)
}

pub fn decode_and_convert(&mut self, jpeg: &[u8]) -> Result<&mut Surface> {
self.decode(jpeg)?;

let mut pppbuf = ProcPipelineParameterBuffer::new(&self.jpeg_surface);
// The input color space is the JPEG color space
let input_props = ColorProperties::new().with_color_range(SourceRange::FULL);
pppbuf.set_input_color_properties(input_props);
pppbuf.set_input_color_standard(ColorStandardType::BT601);
// The output color space is 8-bit non-linear sRGB
let output_props = ColorProperties::new().with_color_range(SourceRange::FULL);
pppbuf.set_output_color_properties(output_props);
pppbuf.set_output_color_standard(ColorStandardType::SRGB);

let mut pppbuf =
Buffer::new_param(&self.vpp_context, BufferType::ProcPipelineParameter, pppbuf)?;

let mut picture = self.vpp_context.begin_picture(&mut self.vpp_surface)?;
picture.render_picture(&mut pppbuf)?;
unsafe { picture.end_picture()? }

drop(pppbuf);

Ok(&mut self.vpp_surface)
}
}
6 changes: 6 additions & 0 deletions src/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,12 @@ impl Surface {
/// [`VAError::ERROR_OPERATION_FAILED`] if it's not supported. In that case, the caller should
/// fall back to creating an [`Image`] manually and using [`Surface::copy_to_image`]. The
/// [`SurfaceWithImage`] type encapsulates that pattern and should be used for this if possible.
///
/// # Bugs
///
/// - Mesa has a bug in its implementation of `vaDeriveImage` where the resulting [`Image`]
/// won't be mapped correctly and appear completely blank if this method is called before a
/// decode operation is submitted.
pub fn derive_image(&mut self) -> Result<Image> {
unsafe {
let mut image = MaybeUninit::uninit();
Expand Down

0 comments on commit 9f1cf72

Please sign in to comment.