#[cfg(not(target_arch = "wasm32"))]
pub mod gpu;
#[cfg(not(target_arch = "wasm32"))]
pub use gpu::{
clamp_surface_size, surface_acquire_action, CopySrc, FrameAcquire, Gpu, GpuConfig,
GpuInitError, RetryWake, SurfaceAcquire, SurfaceError,
};
#[cfg(not(target_arch = "wasm32"))]
mod surface_retry;
pub mod custom_render;
pub use custom_render::{SharedCustomRenderer, WgpuCustomRender, WgpuCustomRenderCtx};
pub mod ssaa;
pub use ssaa::{ssaa_linear_scale, SsaaFramebuffer};
mod screenshot_readback;
#[derive(Clone)]
#[non_exhaustive]
pub struct WgpuPaintContext {
pub device: Arc<wgpu::Device>,
pub queue: Arc<wgpu::Queue>,
pub target_view: wgpu::TextureView,
pub surface_format: wgpu::TextureFormat,
pub target_size: (u32, u32),
}
mod aa_step;
mod buffer_arena;
mod ctx_core;
mod draw_command;
pub(crate) use draw_command::DrawCommand;
mod draw_ctx_impl;
mod end_frame;
mod end_frame_prepare;
mod gradient;
mod image_blit;
mod layer_mask;
mod layers;
pub mod pipelines;
mod primitives;
mod screenshot_capture;
mod screenshot_scaled;
pub use screenshot_scaled::RectInPixels;
mod shaders;
mod text_render;
#[cfg(test)]
mod clip_path_readback_tests;
#[cfg(test)]
mod frame_release_tests;
#[cfg(test)]
mod image_blit_readback_tests;
#[cfg(test)]
mod layer_text_readback_tests;
#[cfg(test)]
mod lcd_arc_cache_tests;
#[cfg(test)]
mod screenshot_scaled_tests;
use std::collections::{HashMap, VecDeque};
use std::sync::{Arc, Weak};
use agg_gui::color::Color;
use agg_gui::draw_ctx::{FillRule, LinearGradientPaint, RadialGradientPaint};
use agg_gui::gl_renderer::GlyphCache;
use agg_gui::text::Font;
use agg_gui::TransAffine;
use agg_gui::{LineCap, LineJoin};
use agg_rust::path_storage::PathStorage;
use pipelines::WgpuPipelines;
pub(crate) struct ArcTextureEntry {
pub(crate) weak: Weak<Vec<u8>>,
pub(crate) texture: Arc<wgpu::Texture>,
pub(crate) view: wgpu::TextureView,
pub(crate) w: u32,
pub(crate) h: u32,
}
pub(crate) struct LcdArcTextureEntry {
pub(crate) weak: Weak<Vec<u8>>,
pub(crate) texture: Arc<wgpu::Texture>,
pub(crate) view: wgpu::TextureView,
pub(crate) w: u32,
pub(crate) h: u32,
pub(crate) version: u64,
}
#[derive(Clone)]
pub(crate) struct SavedWgpuDrawState {
pub(crate) viewport: (f32, f32),
pub(crate) fill_color: Color,
pub(crate) fill_linear_gradient: Option<LinearGradientPaint>,
pub(crate) fill_radial_gradient: Option<RadialGradientPaint>,
pub(crate) stroke_color: Color,
pub(crate) stroke_linear_gradient: Option<LinearGradientPaint>,
pub(crate) stroke_radial_gradient: Option<RadialGradientPaint>,
pub(crate) line_width: f64,
pub(crate) line_join: LineJoin,
pub(crate) line_cap: LineCap,
pub(crate) fill_rule: FillRule,
pub(crate) miter_limit: f64,
pub(crate) line_dash: Vec<f64>,
pub(crate) dash_offset: f64,
pub(crate) global_alpha: f64,
pub(crate) state_stack: Vec<(TransAffine, Option<[i32; 4]>)>,
pub(crate) font: Option<Arc<Font>>,
pub(crate) font_size: f64,
pub(crate) lcd_mode: bool,
}
#[derive(Clone, Copy)]
pub(crate) struct LayerRoundedClip {
pub(crate) x: f32,
pub(crate) y: f32,
pub(crate) w: f32,
pub(crate) h: f32,
pub(crate) r: f32,
}
pub(crate) struct WgpuLayerEntry {
pub(crate) texture: Arc<wgpu::Texture>,
pub(crate) view: wgpu::TextureView,
pub(crate) width: u32,
pub(crate) height: u32,
pub(crate) origin_x: f64,
pub(crate) origin_y: f64,
pub(crate) alpha: f64,
pub(crate) saved: SavedWgpuDrawState,
pub(crate) retained_key: Option<u64>,
pub(crate) rounded_clip: Option<LayerRoundedClip>,
pub(crate) parent_clip: Option<[i32; 4]>,
pub(crate) opaque_backdrop: bool,
pub(crate) clip_mask: Option<crate::layer_mask::ClipMaskMesh>,
pub(crate) clip_saved_path: Option<PathStorage>,
}
pub(crate) struct RetainedWgpuLayer {
pub(crate) texture: Arc<wgpu::Texture>,
pub(crate) view: wgpu::TextureView,
pub(crate) width: u32,
pub(crate) height: u32,
pub(crate) rounded_clip: Option<LayerRoundedClip>,
}
pub(crate) struct PendingReadback {
staging: wgpu::Buffer,
w: u32,
h: u32,
padded_bpr: u32,
done: std::sync::mpsc::Receiver<Result<(), wgpu::BufferAsyncError>>,
}
pub struct WgpuGfxCtx {
pub(crate) device: Arc<wgpu::Device>,
pub(crate) queue: Arc<wgpu::Queue>,
pub(crate) surface_format: wgpu::TextureFormat,
pub(crate) viewport: (f32, f32),
pub(crate) pipelines: WgpuPipelines,
pub(crate) commands: Vec<DrawCommand>,
pub(crate) texture_cache: HashMap<u64, (Arc<wgpu::Texture>, wgpu::TextureView, u32, u32)>,
pub(crate) texture_cache_order: VecDeque<u64>,
pub(crate) arc_texture_cache: HashMap<usize, ArcTextureEntry>,
pub(crate) lcd_arc_texture_cache: HashMap<usize, LcdArcTextureEntry>,
pub(crate) layer_stack: Vec<WgpuLayerEntry>,
pub(crate) retained_layers: HashMap<u64, RetainedWgpuLayer>,
pub(crate) fill_color: Color,
pub(crate) fill_linear_gradient: Option<LinearGradientPaint>,
pub(crate) fill_radial_gradient: Option<RadialGradientPaint>,
pub(crate) stroke_color: Color,
pub(crate) stroke_linear_gradient: Option<LinearGradientPaint>,
pub(crate) stroke_radial_gradient: Option<RadialGradientPaint>,
pub(crate) line_width: f64,
pub(crate) line_join: LineJoin,
pub(crate) line_cap: LineCap,
pub(crate) fill_rule: FillRule,
pub(crate) miter_limit: f64,
pub(crate) line_dash: Vec<f64>,
pub(crate) dash_offset: f64,
pub(crate) global_alpha: f64,
pub(crate) state_stack: Vec<(TransAffine, Option<[i32; 4]>)>,
pub(crate) path: PathStorage,
pub(crate) font: Option<Arc<Font>>,
pub(crate) font_size: f64,
pub(crate) lcd_mode: bool,
pub(crate) glyph_cache: GlyphCache,
pub(crate) surface_view: Option<wgpu::TextureView>,
pub(crate) surface_texture: Option<wgpu::Texture>,
pub(crate) warned_unreleased_frame: bool,
pub(crate) pending_screenshot: Option<(Vec<u8>, u32, u32)>,
pub(crate) capture_texture: Option<(Arc<wgpu::Texture>, wgpu::TextureView, u32, u32)>,
pub(crate) pending_readback: Option<PendingReadback>,
pub(crate) pending_scaled_readback: Option<PendingReadback>,
pub(crate) scaled_blit: Option<screenshot_scaled::ScaledBlit>,
pub(crate) frame_arenas: buffer_arena::FrameArenas,
#[allow(dead_code)]
pub(crate) aa_step_texture: Arc<wgpu::Texture>,
#[allow(dead_code)]
pub(crate) aa_step_view: wgpu::TextureView,
pub(crate) aa_step_bg1: Arc<wgpu::BindGroup>,
pub(crate) last_end_frame_stats: LastEndFrameStats,
}
#[derive(Debug, Default, Clone, Copy)]
pub struct LastEndFrameStats {
pub prepare_us: u32,
pub execute_us: u32,
pub submit_us: u32,
pub command_count: u32,
}
impl WgpuGfxCtx {
pub fn new(
device: Arc<wgpu::Device>,
queue: Arc<wgpu::Queue>,
surface_format: wgpu::TextureFormat,
width: f32,
height: f32,
) -> Self {
let pipelines = WgpuPipelines::new(&device, surface_format, 1);
let frame_arenas = buffer_arena::FrameArenas::new(&device);
let aa_step_texture = aa_step::build_aa_step_texture(&device, &queue);
let aa_step_view = aa_step_texture.create_view(&wgpu::TextureViewDescriptor::default());
let aa_step_bg1 = Arc::new(device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("aa_step_bg1"),
layout: &pipelines.aa_texture_bgl1,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&aa_step_view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&pipelines.linear_sampler),
},
],
}));
let aa_step_texture = Arc::new(aa_step_texture);
Self {
device,
queue,
surface_format,
viewport: (width, height),
pipelines,
commands: Vec::new(),
texture_cache: HashMap::new(),
texture_cache_order: VecDeque::new(),
arc_texture_cache: HashMap::new(),
lcd_arc_texture_cache: HashMap::new(),
layer_stack: Vec::new(),
retained_layers: HashMap::new(),
fill_color: Color::rgba(0.0, 0.0, 0.0, 1.0),
fill_linear_gradient: None,
fill_radial_gradient: None,
stroke_color: Color::rgba(0.0, 0.0, 0.0, 1.0),
stroke_linear_gradient: None,
stroke_radial_gradient: None,
line_width: 1.0,
line_join: LineJoin::Miter,
line_cap: LineCap::Butt,
fill_rule: FillRule::NonZero,
miter_limit: 4.0,
line_dash: Vec::new(),
dash_offset: 0.0,
global_alpha: 1.0,
state_stack: vec![(TransAffine::new(), None)],
path: PathStorage::new(),
font: None,
font_size: 16.0,
lcd_mode: false,
glyph_cache: GlyphCache::new(),
surface_view: None,
surface_texture: None,
warned_unreleased_frame: false,
pending_screenshot: None,
capture_texture: None,
pending_readback: None,
pending_scaled_readback: None,
scaled_blit: None,
frame_arenas,
aa_step_texture,
aa_step_view,
aa_step_bg1,
last_end_frame_stats: LastEndFrameStats::default(),
}
}
pub fn last_end_frame_stats(&self) -> LastEndFrameStats {
self.last_end_frame_stats
}
pub fn reset(&mut self, width: f32, height: f32) {
self.viewport = (width, height);
self.fill_color = Color::rgba(0.0, 0.0, 0.0, 1.0);
self.fill_linear_gradient = None;
self.fill_radial_gradient = None;
self.stroke_color = Color::rgba(0.0, 0.0, 0.0, 1.0);
self.stroke_linear_gradient = None;
self.stroke_radial_gradient = None;
self.line_width = 1.0;
self.fill_rule = FillRule::NonZero;
self.miter_limit = 4.0;
self.line_dash.clear();
self.dash_offset = 0.0;
self.global_alpha = 1.0;
self.state_stack = vec![(TransAffine::new(), None)];
self.path = PathStorage::new();
self.font = None;
self.font_size = 16.0;
self.commands.clear();
self.layer_stack.clear();
}
pub fn set_lcd_mode(&mut self, on: bool) {
self.lcd_mode = on;
}
pub fn begin_frame(&mut self, view: wgpu::TextureView) {
self.surface_view = Some(view);
let bg = agg_gui::current_visuals().bg_color;
self.commands.push(DrawCommand::Clear(bg));
self.set_lcd_mode(agg_gui::font_settings::lcd_enabled());
}
pub fn end_frame(&mut self) {
let Some(view) = self.surface_view.take() else {
return;
};
self.flush_to_surface(&view);
}
pub fn pipelines(&self) -> &pipelines::WgpuPipelines {
&self.pipelines
}
pub fn device(&self) -> &Arc<wgpu::Device> {
&self.device
}
pub fn queue(&self) -> &Arc<wgpu::Queue> {
&self.queue
}
pub fn surface_format(&self) -> wgpu::TextureFormat {
self.surface_format
}
pub fn push_custom_render(
&mut self,
renderer: custom_render::SharedCustomRenderer,
screen_rect: agg_gui::Rect,
) {
let parent_clip = self.current_clip();
self.commands.push(DrawCommand::Custom {
renderer,
screen_rect,
parent_clip,
});
}
}