Skip to main content

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