webrender/
filterdata.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use std::hash;
6use crate::gpu_cache::{GpuCache, GpuCacheHandle};
7use crate::gpu_cache::GpuDataRequest;
8use crate::intern;
9use api::ComponentTransferFuncType;
10
11
12pub type FilterDataHandle = intern::Handle<FilterDataIntern>;
13
14#[derive(Debug, Clone, MallocSizeOf, PartialEq)]
15#[cfg_attr(feature = "capture", derive(Serialize))]
16#[cfg_attr(feature = "replay", derive(Deserialize))]
17pub enum SFilterDataComponent {
18    Identity,
19    Table(Vec<f32>),
20    Discrete(Vec<f32>),
21    Linear(f32, f32),
22    Gamma(f32, f32, f32),
23}
24
25impl Eq for SFilterDataComponent {}
26
27impl hash::Hash for SFilterDataComponent {
28    fn hash<H: hash::Hasher>(&self, state: &mut H) {
29        match self {
30            SFilterDataComponent::Identity => {
31                0.hash(state);
32            }
33            SFilterDataComponent::Table(values) => {
34                1.hash(state);
35                values.len().hash(state);
36                for val in values {
37                    val.to_bits().hash(state);
38                }
39            }
40            SFilterDataComponent::Discrete(values) => {
41                2.hash(state);
42                values.len().hash(state);
43                for val in values {
44                    val.to_bits().hash(state);
45                }
46            }
47            SFilterDataComponent::Linear(a, b) => {
48                3.hash(state);
49                a.to_bits().hash(state);
50                b.to_bits().hash(state);
51            }
52            SFilterDataComponent::Gamma(a, b, c) => {
53                4.hash(state);
54                a.to_bits().hash(state);
55                b.to_bits().hash(state);
56                c.to_bits().hash(state);
57            }
58        }
59    }
60}
61
62impl SFilterDataComponent {
63    pub fn to_int(&self) -> u32 {
64        match self {
65            SFilterDataComponent::Identity => 0,
66            SFilterDataComponent::Table(_) => 1,
67            SFilterDataComponent::Discrete(_) => 2,
68            SFilterDataComponent::Linear(_, _) => 3,
69            SFilterDataComponent::Gamma(_, _, _) => 4,
70        }
71    }
72
73    pub fn from_functype_values(
74        func_type: ComponentTransferFuncType,
75        values: &[f32],
76    ) -> SFilterDataComponent {
77        match func_type {
78            ComponentTransferFuncType::Identity => SFilterDataComponent::Identity,
79            ComponentTransferFuncType::Table => SFilterDataComponent::Table(values.to_vec()),
80            ComponentTransferFuncType::Discrete => SFilterDataComponent::Discrete(values.to_vec()),
81            ComponentTransferFuncType::Linear => SFilterDataComponent::Linear(values[0], values[1]),
82            ComponentTransferFuncType::Gamma => SFilterDataComponent::Gamma(values[0], values[1], values[2]),
83        }
84    }
85}
86
87#[derive(Debug, Clone, MallocSizeOf, PartialEq, Eq, Hash)]
88#[cfg_attr(feature = "capture", derive(Serialize))]
89#[cfg_attr(feature = "replay", derive(Deserialize))]
90pub struct SFilterData {
91    pub r_func: SFilterDataComponent,
92    pub g_func: SFilterDataComponent,
93    pub b_func: SFilterDataComponent,
94    pub a_func: SFilterDataComponent,
95}
96
97#[derive(Debug, Clone, MallocSizeOf, PartialEq, Eq, Hash)]
98#[cfg_attr(feature = "capture", derive(Serialize))]
99#[cfg_attr(feature = "replay", derive(Deserialize))]
100pub struct SFilterDataKey {
101    pub data: SFilterData,
102}
103
104impl intern::InternDebug for SFilterDataKey {}
105
106#[derive(Debug)]
107#[cfg_attr(feature = "capture", derive(Serialize))]
108#[cfg_attr(feature = "replay", derive(Deserialize))]
109#[derive(MallocSizeOf)]
110pub struct SFilterDataTemplate {
111    pub data: SFilterData,
112    pub gpu_cache_handle: GpuCacheHandle,
113}
114
115impl From<SFilterDataKey> for SFilterDataTemplate {
116    fn from(item: SFilterDataKey) -> Self {
117        SFilterDataTemplate {
118            data: item.data,
119            gpu_cache_handle: GpuCacheHandle::new(),
120        }
121    }
122}
123
124impl SFilterData {
125    pub fn is_identity(&self) -> bool {
126        self.r_func == SFilterDataComponent::Identity
127            && self.g_func == SFilterDataComponent::Identity
128            && self.b_func == SFilterDataComponent::Identity
129            && self.a_func == SFilterDataComponent::Identity
130    }
131
132    pub fn update(&self, mut request: GpuDataRequest) {
133        push_component_transfer_data(&self.r_func, &mut request);
134        push_component_transfer_data(&self.g_func, &mut request);
135        push_component_transfer_data(&self.b_func, &mut request);
136        push_component_transfer_data(&self.a_func, &mut request);
137        assert!(!self.is_identity());
138    }
139}
140
141impl SFilterDataTemplate {
142    /// Update the GPU cache for a given filter data template. This may be called multiple
143    /// times per frame, by each primitive reference that refers to this interned
144    /// template. The initial request call to the GPU cache ensures that work is only
145    /// done if the cache entry is invalid (due to first use or eviction).
146    pub fn update(
147        &mut self,
148        gpu_cache: &mut GpuCache,
149    ) {
150        if let Some(request) = gpu_cache.request(&mut self.gpu_cache_handle) {
151            self.data.update(request);
152        }
153    }
154}
155
156#[derive(Copy, Clone, Debug, MallocSizeOf)]
157#[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))]
158pub enum FilterDataIntern {}
159
160impl intern::Internable for FilterDataIntern {
161    type Key = SFilterDataKey;
162    type StoreData = SFilterDataTemplate;
163    type InternData = ();
164    const PROFILE_COUNTER: usize = crate::profiler::INTERNED_FILTER_DATA;
165}
166
167fn push_component_transfer_data(
168    func_comp: &SFilterDataComponent,
169    request: &mut GpuDataRequest,
170) {
171    match func_comp {
172        SFilterDataComponent::Identity => {}
173        SFilterDataComponent::Table(values) |
174        SFilterDataComponent::Discrete(values) => {
175            // Push a 256 entry lookup table.
176            assert!(values.len() > 0);
177            for i in 0 .. 64 {
178                let mut arr = [0.0 ; 4];
179                for j in 0 .. 4 {
180                    if (values.len() == 1) || (i == 63 && j == 3) {
181                        arr[j] = values[values.len()-1];
182                    } else {
183                        let c = ((4*i + j) as f32)/255.0;
184                        match func_comp {
185                            SFilterDataComponent::Table(_) => {
186                                let n = (values.len()-1) as f32;
187                                let k = (n * c).floor() as u32;
188                                let ku = k as usize;
189                                assert!(ku < values.len()-1);
190                                arr[j] = values[ku] + (c*n - (k as f32)) * (values[ku+1] - values[ku]);
191                            }
192                            SFilterDataComponent::Discrete(_) => {
193                                let n = values.len() as f32;
194                                let k = (n * c).floor() as usize;
195                                assert!(k < values.len());
196                                arr[j] = values[k];
197                            }
198                            SFilterDataComponent::Identity |
199                            SFilterDataComponent::Linear(_,_) |
200                            SFilterDataComponent::Gamma(_,_,_) => {
201                                unreachable!();
202                            }
203                        }
204
205                    }
206                }
207
208                request.push(arr);
209            }
210        }
211        SFilterDataComponent::Linear(a, b) => {
212            request.push([*a, *b, 0.0, 0.0]);
213        }
214        SFilterDataComponent::Gamma(a, b, c) => {
215            request.push([*a, *b, *c, 0.0]);
216        }
217    }
218}