mod compositor;
mod layer;
mod pipeline;
mod pool;
mod readback;
mod shader;
mod target;
#[cfg(test)]
mod tests;
pub use compositor::{Background, Compositor, PresentTarget};
use crate::backends::coverage::RenderBitmap;
use crate::backends::software::SoftwareBackend;
use crate::backends::{BackendFeature, BackendType, RenderBackend};
use crate::pipeline::{IntermediateLayer, Pipeline, SoftwarePipeline};
use crate::renderer::RenderContext;
use crate::utils::RenderError;
pub struct GpuBackend {
device: wgpu::Device,
queue: wgpu::Queue,
software: SoftwareBackend,
compositor: Compositor,
}
impl GpuBackend {
pub fn new(width: u32, height: u32) -> Result<Self, RenderError> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
..Default::default()
});
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
compatible_surface: None,
force_fallback_adapter: false,
}))
.ok_or_else(|| RenderError::BackendError("no wgpu adapter available".into()))?;
let (device, queue) = pollster::block_on(adapter.request_device(
&wgpu::DeviceDescriptor {
label: Some("ass-gpu-device"),
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::default(),
},
None,
))
.map_err(|e| RenderError::BackendError(format!("wgpu request_device failed: {e}")))?;
let context = RenderContext::new(width, height);
let software = SoftwareBackend::new(&context)?;
let compositor = Compositor::new(&device);
Ok(Self {
device,
queue,
software,
compositor,
})
}
pub fn composite_bitmaps(
&mut self,
bitmaps: &[RenderBitmap],
width: u32,
height: u32,
) -> Result<Vec<u8>, RenderError> {
self.compositor
.composite(&self.device, &self.queue, bitmaps, width, height)
}
pub fn render_subtitle_layer(
&mut self,
bitmaps: &[RenderBitmap],
width: u32,
height: u32,
) -> Result<(), RenderError> {
self.compositor
.render_layer(&self.device, &self.queue, bitmaps, width, height)
}
pub fn present_frame(&mut self, width: u32, height: u32) -> Result<(), RenderError> {
self.compositor.present_over(
&self.device,
&self.queue,
Background::Clear(wgpu::Color::BLACK),
width,
height,
)
}
pub fn layer_to_bytes(&self) -> Result<Vec<u8>, RenderError> {
self.compositor.layer_to_bytes(&self.device, &self.queue)
}
}
impl RenderBackend for GpuBackend {
fn backend_type(&self) -> BackendType {
BackendType::Gpu
}
fn create_pipeline(&self) -> Result<Box<dyn Pipeline>, RenderError> {
Ok(Box::new(SoftwarePipeline::new()))
}
fn composite_layers(
&mut self,
layers: &[IntermediateLayer],
context: &RenderContext,
) -> Result<Vec<u8>, RenderError> {
let bitmaps = self.software.render_layers_to_bitmaps(layers, context)?;
self.compositor.composite(
&self.device,
&self.queue,
&bitmaps,
context.width(),
context.height(),
)
}
fn render_layers_to_bitmaps(
&mut self,
layers: &[IntermediateLayer],
context: &RenderContext,
) -> Result<Vec<RenderBitmap>, RenderError> {
self.software.render_layers_to_bitmaps(layers, context)
}
fn supports_feature(&self, feature: BackendFeature) -> bool {
matches!(feature, BackendFeature::HardwareAcceleration)
}
}