comfy_core/
render_queues.rs

1use crate::*;
2
3static SHADER_UNIFORM_TABLE: Lazy<AtomicRefCell<ShaderUniformTable>> =
4    Lazy::new(|| AtomicRefCell::new(ShaderUniformTable::default()));
5
6#[derive(Default)]
7pub struct ShaderUniformTable {
8    instances: Vec<ShaderInstance>,
9}
10
11pub fn clear_shader_uniform_table() {
12    SHADER_UNIFORM_TABLE.borrow_mut().instances.clear();
13}
14
15pub fn get_shader_instance(
16    id: ShaderInstanceId,
17) -> AtomicRef<'static, ShaderInstance> {
18    AtomicRef::map(SHADER_UNIFORM_TABLE.borrow(), |x| {
19        &x.instances[id.0 as usize]
20    })
21}
22
23pub fn set_uniform(name: impl Into<String>, value: Uniform) {
24    let instance_id = CURRENT_SHADER_INSTANCE_ID.load(Ordering::SeqCst);
25
26    if instance_id > 0 {
27        let mut table = SHADER_UNIFORM_TABLE.borrow_mut();
28
29        if let Some(instance) = table.instances.get(instance_id as usize) {
30            let mut new_instance = instance.clone();
31            new_instance.uniforms.insert(name.into(), value);
32
33            table.instances.push(new_instance);
34
35            CURRENT_SHADER_INSTANCE_ID
36                .store(table.instances.len() as u32 - 1, Ordering::SeqCst);
37        } else {
38            panic!(
39    "Current shader instance id is invalid.
40
41                This is likely a bug, \
42     please report an issue on https://github.com/darthdeus/comfy/issues with \
43     some information on what you did."
44);
45        }
46    } else {
47        panic!("Trying to set a uniform with no shader active");
48    }
49}
50
51static CURRENT_SHADER_INSTANCE_ID: AtomicU32 = AtomicU32::new(0);
52
53/// Switches to the shader with the given ID. The shader must already exist. To revert back to the
54/// default shader simply call `use_default_shader()`.
55pub fn use_shader(shader_id: ShaderId) {
56    let mut table = SHADER_UNIFORM_TABLE.borrow_mut();
57
58    table
59        .instances
60        .push(ShaderInstance { id: shader_id, uniforms: Default::default() });
61
62    CURRENT_SHADER_INSTANCE_ID
63        .store(table.instances.len() as u32 - 1, Ordering::SeqCst);
64}
65
66/// Switches back to the default shader.
67pub fn use_default_shader() {
68    CURRENT_SHADER_INSTANCE_ID.store(0, Ordering::SeqCst);
69}
70
71/// Returns the current `ShaderInstance` if any. Currently intended only for internal use.
72pub fn get_current_shader() -> ShaderInstanceId {
73    // TODO: we probably don't need SeqCst for any of these, but that can be fixed later
74    ShaderInstanceId(CURRENT_SHADER_INSTANCE_ID.load(Ordering::SeqCst))
75}
76
77use std::{
78    collections::BTreeMap,
79    sync::atomic::{AtomicU32, AtomicU64, Ordering},
80};
81
82static SHADER_IDS: AtomicU64 = AtomicU64::new(0);
83
84/// Generates a new ShaderId. This is intended for internal use only.
85pub fn gen_shader_id() -> ShaderId {
86    let id = SHADER_IDS.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
87
88    info!("Generated ShaderId: {}", id);
89
90    ShaderId(id)
91}
92
93/// Represents a set of shader uniform parameters.
94///
95/// u32 ID is exposed for debugging purposes only, do not modify by hand.
96#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
97pub struct ShaderInstanceId(pub u32);
98
99static TEXT_QUEUE: Lazy<AtomicRefCell<Vec<DrawText>>> =
100    Lazy::new(|| AtomicRefCell::new(Vec::new()));
101
102pub fn consume_text_queue() -> Vec<DrawText> {
103    let mut queue = TEXT_QUEUE.borrow_mut();
104    let mut new_data = Vec::new();
105    std::mem::swap(&mut *queue, &mut new_data);
106    new_data
107}
108
109static RENDER_QUEUES: Lazy<AtomicRefCell<RenderQueues>> =
110    Lazy::new(|| AtomicRefCell::new(RenderQueues::default()));
111
112pub type RenderQueue = Vec<Mesh>;
113
114#[derive(Default)]
115struct RenderQueues {
116    data: BTreeMap<MeshGroupKey, RenderQueue>,
117}
118
119#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
120pub struct MeshGroupKey {
121    pub z_index: i32,
122    pub blend_mode: BlendMode,
123    pub texture_id: TextureHandle,
124    pub shader: ShaderInstanceId,
125    pub render_target: RenderTargetId,
126}
127
128pub fn consume_render_queues() -> BTreeMap<MeshGroupKey, RenderQueue> {
129    let mut queues = RENDER_QUEUES.borrow_mut();
130    let mut new_data = BTreeMap::new();
131    std::mem::swap(&mut new_data, &mut queues.data);
132    new_data
133}
134
135pub fn queue_mesh_draw(mesh: Mesh, blend_mode: BlendMode) {
136    let shader = get_current_shader();
137    let render_target = get_current_render_target();
138
139    RENDER_QUEUES
140        .borrow_mut()
141        .data
142        .entry(MeshGroupKey {
143            z_index: mesh.z_index,
144            blend_mode,
145            texture_id: mesh
146                .texture
147                .unwrap_or_else(|| TextureHandle::from_path("1px")),
148            shader,
149            render_target,
150        })
151        .or_default()
152        .push(mesh);
153}
154
155pub fn draw_text_internal(
156    text: TextData,
157    position: Vec2,
158    align: TextAlign,
159    pro_params: Option<ProTextParams>,
160    params: TextParams,
161) {
162    TEXT_QUEUE.borrow_mut().push(DrawText {
163        text,
164        position,
165        color: params.color,
166        font: params.font,
167        align,
168        pro_params,
169        z_index: params.z_index,
170    });
171}