use crate::backends::gpu::pool::{QuadUniform, UNIFORM_SIZE};
use crate::utils::RenderError;
use super::Compositor;
#[derive(Clone, Copy)]
pub enum Background<'a> {
Clear(wgpu::Color),
Texture(&'a wgpu::TextureView),
}
#[derive(Clone, Copy)]
pub struct PresentTarget<'a> {
pub view: &'a wgpu::TextureView,
pub format: wgpu::TextureFormat,
}
pub(super) fn run(
comp: &Compositor,
device: &wgpu::Device,
queue: &wgpu::Queue,
background: Background,
quad_count: u32,
) -> Result<(), RenderError> {
let screen = comp.screen.as_ref().expect("screen set by caller");
encode(
comp,
device,
queue,
&comp.pipeline,
screen.view(),
background,
quad_count,
)?;
device.poll(wgpu::Maintain::Wait);
Ok(())
}
pub(super) fn run_to_view(
comp: &Compositor,
device: &wgpu::Device,
queue: &wgpu::Queue,
target_view: &wgpu::TextureView,
target_format: wgpu::TextureFormat,
background: Background,
quad_count: u32,
) -> Result<(), RenderError> {
let pipeline = comp.present_pipelines.get(&target_format).ok_or_else(|| {
RenderError::BackendError("present_to_view missing format-matched pipeline".into())
})?;
encode(
comp,
device,
queue,
pipeline,
target_view,
background,
quad_count,
)
}
fn encode(
comp: &Compositor,
device: &wgpu::Device,
queue: &wgpu::Queue,
pipeline: &wgpu::RenderPipeline,
target: &wgpu::TextureView,
background: Background,
quad_count: u32,
) -> Result<(), RenderError> {
let stride = comp.uniform_stride as usize;
let mut bytes = vec![0u8; stride * quad_count as usize];
let full = QuadUniform::full_frame_rgba();
for slot in 0..quad_count as usize {
let off = slot * stride;
bytes[off..off + UNIFORM_SIZE as usize].copy_from_slice(full.as_bytes());
}
let Some(uniforms) = comp.uniforms.as_ref() else {
return Err(RenderError::BackendError(
"present pass missing uniform buffer".into(),
));
};
queue.write_buffer(&uniforms.buffer, 0, &bytes);
let bg_bind = match background {
Background::Texture(view) => Some(device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("ass-gpu-bg-bind"),
layout: &comp.tile_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(view),
}],
})),
Background::Clear(_) => None,
};
let load = match background {
Background::Clear(color) => wgpu::LoadOp::Clear(color),
Background::Texture(_) => wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
};
let layer = comp
.layer
.as_ref()
.expect("layer presence checked by caller");
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("ass-gpu-present-encoder"),
});
{
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("ass-gpu-present-pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: target,
resolve_target: None,
ops: wgpu::Operations {
load,
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
});
pass.set_pipeline(pipeline);
let mut offset = 0u32;
if let Some(bind) = bg_bind.as_ref() {
pass.set_bind_group(0, &uniforms.bind_group, &[offset]);
pass.set_bind_group(1, bind, &[]);
pass.draw(0..6, 0..1);
offset += comp.uniform_stride;
}
pass.set_bind_group(0, &uniforms.bind_group, &[offset]);
pass.set_bind_group(1, layer.bind_group(), &[]);
pass.draw(0..6, 0..1);
}
queue.submit(Some(encoder.finish()));
Ok(())
}