Skip to main content

pathfinder_renderer/gpu/
renderer.rs

1// pathfinder/renderer/src/gpu/renderer.rs
2//
3// Copyright © 2020 The Pathfinder Project Developers.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11use crate::gpu::debug::DebugUIPresenter;
12use crate::gpu::options::{DestFramebuffer, RendererOptions};
13use crate::gpu::shaders::{BlitProgram, BlitVertexArray, CopyTileProgram, CopyTileVertexArray};
14use crate::gpu::shaders::{FillProgram, FillVertexArray, MAX_FILLS_PER_BATCH, ReprojectionProgram};
15use crate::gpu::shaders::{ReprojectionVertexArray, StencilProgram, StencilVertexArray};
16use crate::gpu::shaders::{TileProgram, TileVertexArray};
17use crate::gpu_data::{Fill, FillBatchEntry, RenderCommand, TextureLocation};
18use crate::gpu_data::{TextureMetadataEntry, TexturePageDescriptor, TexturePageId};
19use crate::gpu_data::{Tile, TileBatchTexture};
20use crate::options::BoundingQuad;
21use crate::paint::PaintCompositeOp;
22use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
23use half::f16;
24use pathfinder_color::{self as color, ColorF, ColorU};
25use pathfinder_content::effects::{BlendMode, BlurDirection, DefringingKernel};
26use pathfinder_content::effects::{Filter, PatternFilter};
27use pathfinder_content::fill::FillRule;
28use pathfinder_content::render_target::RenderTargetId;
29use pathfinder_geometry::line_segment::LineSegment2F;
30use pathfinder_geometry::rect::RectI;
31use pathfinder_geometry::transform3d::Transform4F;
32use pathfinder_geometry::util;
33use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F, vec2f, vec2i};
34use pathfinder_gpu::{BlendFactor, BlendState, BufferData, BufferTarget, BufferUploadMode};
35use pathfinder_gpu::{ClearOps, DepthFunc, DepthState, Device, Primitive, RenderOptions};
36use pathfinder_gpu::{RenderState, RenderTarget, StencilFunc, StencilState, TextureDataRef};
37use pathfinder_gpu::{TextureFormat, UniformData};
38use pathfinder_resources::ResourceLoader;
39use pathfinder_simd::default::{F32x2, F32x4, I32x2};
40use std::collections::VecDeque;
41use std::f32;
42use std::mem;
43use std::ops::{Add, Div};
44use std::time::Duration;
45use std::u32;
46
47static QUAD_VERTEX_POSITIONS: [u16; 8] = [0, 0, 1, 0, 1, 1, 0, 1];
48static QUAD_VERTEX_INDICES: [u32; 6] = [0, 1, 3, 1, 2, 3];
49
50pub(crate) const MASK_TILES_ACROSS: u32 = 256;
51pub(crate) const MASK_TILES_DOWN: u32 = 256;
52
53// 1.0 / sqrt(2*pi)
54const SQRT_2_PI_INV: f32 = 0.3989422804014327;
55
56const TEXTURE_CACHE_SIZE: usize = 8;
57const TIMER_QUERY_CACHE_SIZE: usize = 8;
58
59const TEXTURE_METADATA_ENTRIES_PER_ROW: i32 = 128;
60const TEXTURE_METADATA_TEXTURE_WIDTH:   i32 = TEXTURE_METADATA_ENTRIES_PER_ROW * 4;
61const TEXTURE_METADATA_TEXTURE_HEIGHT:  i32 = 65536 / TEXTURE_METADATA_ENTRIES_PER_ROW;
62
63// FIXME(pcwalton): Shrink this again!
64const MASK_FRAMEBUFFER_WIDTH:  i32 = TILE_WIDTH as i32  * MASK_TILES_ACROSS as i32;
65const MASK_FRAMEBUFFER_HEIGHT: i32 = TILE_HEIGHT as i32 * MASK_TILES_DOWN as i32;
66
67const COMBINER_CTRL_MASK_WINDING: i32 =             0x1;
68const COMBINER_CTRL_MASK_EVEN_ODD: i32 =            0x2;
69
70const COMBINER_CTRL_COLOR_COMBINE_SRC_IN: i32 =     0x1;
71const COMBINER_CTRL_COLOR_COMBINE_DEST_IN: i32 =    0x2;
72
73const COMBINER_CTRL_FILTER_RADIAL_GRADIENT: i32 =   0x1;
74const COMBINER_CTRL_FILTER_TEXT: i32 =              0x2;
75const COMBINER_CTRL_FILTER_BLUR: i32 =              0x3;
76
77const COMBINER_CTRL_COMPOSITE_NORMAL: i32 =         0x0;
78const COMBINER_CTRL_COMPOSITE_MULTIPLY: i32 =       0x1;
79const COMBINER_CTRL_COMPOSITE_SCREEN: i32 =         0x2;
80const COMBINER_CTRL_COMPOSITE_OVERLAY: i32 =        0x3;
81const COMBINER_CTRL_COMPOSITE_DARKEN: i32 =         0x4;
82const COMBINER_CTRL_COMPOSITE_LIGHTEN: i32 =        0x5;
83const COMBINER_CTRL_COMPOSITE_COLOR_DODGE: i32 =    0x6;
84const COMBINER_CTRL_COMPOSITE_COLOR_BURN: i32 =     0x7;
85const COMBINER_CTRL_COMPOSITE_HARD_LIGHT: i32 =     0x8;
86const COMBINER_CTRL_COMPOSITE_SOFT_LIGHT: i32 =     0x9;
87const COMBINER_CTRL_COMPOSITE_DIFFERENCE: i32 =     0xa;
88const COMBINER_CTRL_COMPOSITE_EXCLUSION: i32 =      0xb;
89const COMBINER_CTRL_COMPOSITE_HUE: i32 =            0xc;
90const COMBINER_CTRL_COMPOSITE_SATURATION: i32 =     0xd;
91const COMBINER_CTRL_COMPOSITE_COLOR: i32 =          0xe;
92const COMBINER_CTRL_COMPOSITE_LUMINOSITY: i32 =     0xf;
93
94const COMBINER_CTRL_MASK_0_SHIFT: i32 =             0;
95const COMBINER_CTRL_MASK_1_SHIFT: i32 =             2;
96const COMBINER_CTRL_COLOR_FILTER_SHIFT: i32 =       4;
97const COMBINER_CTRL_COLOR_COMBINE_SHIFT: i32 =      6;
98const COMBINER_CTRL_COMPOSITE_SHIFT: i32 =          8;
99
100pub struct Renderer<D>
101where
102    D: Device,
103{
104    // Device
105    pub device: D,
106
107    // Core data
108    dest_framebuffer: DestFramebuffer<D>,
109    options: RendererOptions,
110    blit_program: BlitProgram<D>,
111    fill_program: FillProgram<D>,
112    tile_program: TileProgram<D>,
113    tile_copy_program: CopyTileProgram<D>,
114    blit_vertex_array: BlitVertexArray<D>,
115    tile_vertex_array: TileVertexArray<D>,
116    tile_copy_vertex_array: CopyTileVertexArray<D>,
117    tile_vertex_buffer: D::Buffer,
118    quad_vertex_positions_buffer: D::Buffer,
119    quad_vertex_indices_buffer: D::Buffer,
120    quads_vertex_indices_buffer: D::Buffer,
121    quads_vertex_indices_length: usize,
122    fill_vertex_array: FillVertexArray<D>,
123    alpha_tile_pages: Vec<AlphaTilePage<D>>,
124    dest_blend_framebuffer: D::Framebuffer,
125    intermediate_dest_framebuffer: D::Framebuffer,
126    texture_pages: Vec<Option<TexturePage<D>>>,
127    render_targets: Vec<RenderTargetInfo>,
128    render_target_stack: Vec<RenderTargetId>,
129    texture_metadata_texture: D::Texture,
130    area_lut_texture: D::Texture,
131    gamma_lut_texture: D::Texture,
132
133    // Stencil shader
134    stencil_program: StencilProgram<D>,
135    stencil_vertex_array: StencilVertexArray<D>,
136
137    // Reprojection shader
138    reprojection_program: ReprojectionProgram<D>,
139    reprojection_vertex_array: ReprojectionVertexArray<D>,
140
141    // Rendering state
142    framebuffer_flags: FramebufferFlags,
143    texture_cache: TextureCache<D>,
144
145    // Debug
146    pub stats: RenderStats,
147    current_cpu_build_time: Option<Duration>,
148    current_timer: Option<D::TimerQuery>,
149    pending_timers: VecDeque<PendingTimer<D>>,
150    free_timer_queries: Vec<D::TimerQuery>,
151    pub debug_ui_presenter: DebugUIPresenter<D>,
152
153    // Extra info
154    flags: RendererFlags,
155}
156
157impl<D> Renderer<D>
158where
159    D: Device,
160{
161    pub fn new(device: D,
162               resources: &dyn ResourceLoader,
163               dest_framebuffer: DestFramebuffer<D>,
164               options: RendererOptions)
165               -> Renderer<D> {
166        let blit_program = BlitProgram::new(&device, resources);
167        let fill_program = FillProgram::new(&device, resources);
168        let tile_program = TileProgram::new(&device, resources);
169        let tile_copy_program = CopyTileProgram::new(&device, resources);
170        let stencil_program = StencilProgram::new(&device, resources);
171        let reprojection_program = ReprojectionProgram::new(&device, resources);
172
173        let area_lut_texture = device.create_texture_from_png(resources, "area-lut");
174        let gamma_lut_texture = device.create_texture_from_png(resources, "gamma-lut");
175
176        let texture_metadata_texture = device.create_texture(
177            TextureFormat::RGBA16F,
178            Vector2I::new(TEXTURE_METADATA_TEXTURE_WIDTH, TEXTURE_METADATA_TEXTURE_HEIGHT));
179
180        let quad_vertex_positions_buffer = device.create_buffer();
181        device.allocate_buffer(
182            &quad_vertex_positions_buffer,
183            BufferData::Memory(&QUAD_VERTEX_POSITIONS),
184            BufferTarget::Vertex,
185            BufferUploadMode::Static,
186        );
187        let quad_vertex_indices_buffer = device.create_buffer();
188        device.allocate_buffer(
189            &quad_vertex_indices_buffer,
190            BufferData::Memory(&QUAD_VERTEX_INDICES),
191            BufferTarget::Index,
192            BufferUploadMode::Static,
193        );
194        let quads_vertex_indices_buffer = device.create_buffer();
195        let tile_vertex_buffer = device.create_buffer();
196
197        let blit_vertex_array = BlitVertexArray::new(
198            &device,
199            &blit_program,
200            &quad_vertex_positions_buffer,
201            &quad_vertex_indices_buffer,
202        );
203        let fill_vertex_array = FillVertexArray::new(
204            &device,
205            &fill_program,
206            &quad_vertex_positions_buffer,
207            &quad_vertex_indices_buffer,
208        );
209        let tile_vertex_array = TileVertexArray::new(
210            &device,
211            &tile_program,
212            &tile_vertex_buffer,
213            &quad_vertex_positions_buffer,
214            &quad_vertex_indices_buffer,
215        );
216        let tile_copy_vertex_array = CopyTileVertexArray::new(
217            &device,
218            &tile_copy_program,
219            &tile_vertex_buffer,
220            &quads_vertex_indices_buffer,
221        );
222        let stencil_vertex_array = StencilVertexArray::new(&device, &stencil_program);
223        let reprojection_vertex_array = ReprojectionVertexArray::new(
224            &device,
225            &reprojection_program,
226            &quad_vertex_positions_buffer,
227            &quad_vertex_indices_buffer,
228        );
229
230        let window_size = dest_framebuffer.window_size(&device);
231        let dest_blend_texture = device.create_texture(TextureFormat::RGBA8, window_size);
232        let dest_blend_framebuffer = device.create_framebuffer(dest_blend_texture);
233        let intermediate_dest_texture = device.create_texture(TextureFormat::RGBA8, window_size);
234        let intermediate_dest_framebuffer = device.create_framebuffer(intermediate_dest_texture);
235
236        let mut timer_queries = vec![];
237        for _ in 0..TIMER_QUERY_CACHE_SIZE {
238            timer_queries.push(device.create_timer_query());
239        }
240
241        let debug_ui_presenter = DebugUIPresenter::new(&device, resources, window_size);
242
243        Renderer {
244            device,
245
246            dest_framebuffer,
247            options,
248            blit_program,
249            fill_program,
250            tile_program,
251            tile_copy_program,
252            blit_vertex_array,
253            tile_vertex_array,
254            tile_copy_vertex_array,
255            tile_vertex_buffer,
256            quad_vertex_positions_buffer,
257            quad_vertex_indices_buffer,
258            quads_vertex_indices_buffer,
259            quads_vertex_indices_length: 0,
260            fill_vertex_array,
261            alpha_tile_pages: vec![],
262            dest_blend_framebuffer,
263            intermediate_dest_framebuffer,
264            texture_pages: vec![],
265            render_targets: vec![],
266            render_target_stack: vec![],
267
268            area_lut_texture,
269            gamma_lut_texture,
270            texture_metadata_texture,
271
272            stencil_program,
273            stencil_vertex_array,
274
275            reprojection_program,
276            reprojection_vertex_array,
277
278            stats: RenderStats::default(),
279            current_cpu_build_time: None,
280            current_timer: None,
281            pending_timers: VecDeque::new(),
282            free_timer_queries: timer_queries,
283            debug_ui_presenter,
284
285            framebuffer_flags: FramebufferFlags::empty(),
286            texture_cache: TextureCache::new(),
287
288            flags: RendererFlags::empty(),
289        }
290    }
291
292    pub fn begin_scene(&mut self) {
293        self.framebuffer_flags = FramebufferFlags::empty();
294        for alpha_tile_page in &mut self.alpha_tile_pages {
295            alpha_tile_page.must_preserve_framebuffer = false;
296        }
297
298        self.device.begin_commands();
299        self.stats = RenderStats::default();
300    }
301
302    pub fn render_command(&mut self, command: &RenderCommand) {
303        match *command {
304            RenderCommand::Start { bounding_quad, path_count, needs_readable_framebuffer } => {
305                self.start_rendering(bounding_quad, path_count, needs_readable_framebuffer);
306            }
307            RenderCommand::AllocateTexturePage { page_id, ref descriptor } => {
308                self.allocate_texture_page(page_id, descriptor)
309            }
310            RenderCommand::UploadTexelData { ref texels, location } => {
311                self.upload_texel_data(texels, location)
312            }
313            RenderCommand::DeclareRenderTarget { id, location } => {
314                self.declare_render_target(id, location)
315            }
316            RenderCommand::UploadTextureMetadata(ref metadata) => {
317                self.upload_texture_metadata(metadata)
318            }
319            RenderCommand::AddFills(ref fills) => self.add_fills(fills),
320            RenderCommand::FlushFills => {
321                for page_index in 0..(self.alpha_tile_pages.len() as u16) {
322                    self.draw_buffered_fills(page_index)
323                }
324            }
325            RenderCommand::BeginTileDrawing => self.begin_tile_drawing(),
326            RenderCommand::PushRenderTarget(render_target_id) => {
327                self.push_render_target(render_target_id)
328            }
329            RenderCommand::PopRenderTarget => self.pop_render_target(),
330            RenderCommand::DrawTiles(ref batch) => {
331                let count = batch.tiles.len();
332                self.stats.alpha_tile_count += count;
333                self.upload_tiles(&batch.tiles);
334                self.draw_tiles(batch.tile_page,
335                                count as u32,
336                                batch.color_texture,
337                                batch.mask_0_fill_rule,
338                                batch.mask_1_fill_rule,
339                                batch.blend_mode,
340                                batch.filter)
341            }
342            RenderCommand::Finish { cpu_build_time } => self.stats.cpu_build_time = cpu_build_time,
343        }
344    }
345
346    fn begin_tile_drawing(&mut self) {
347        if let Some(timer_query) = self.allocate_timer_query() {
348            self.device.begin_timer_query(&timer_query);
349            self.current_timer = Some(timer_query);
350        }
351    }
352
353    pub fn end_scene(&mut self) {
354        self.blit_intermediate_dest_framebuffer_if_necessary();
355
356        self.device.end_commands();
357
358        if let Some(timer_query) = self.current_timer.take() {
359            self.device.end_timer_query(&timer_query);
360            self.pending_timers.push_back(PendingTimer {
361                gpu_timer_query: timer_query,
362            });
363        }
364        self.current_cpu_build_time = None;
365    }
366
367    fn start_rendering(&mut self,
368                       bounding_quad: BoundingQuad,
369                       path_count: usize,
370                       mut needs_readable_framebuffer: bool) {
371        if let DestFramebuffer::Other(_) = self.dest_framebuffer {
372            needs_readable_framebuffer = false;
373        }
374
375        if self.flags.contains(RendererFlags::USE_DEPTH) {
376            self.draw_stencil(&bounding_quad);
377        }
378        self.stats.path_count = path_count;
379
380        self.flags.set(RendererFlags::INTERMEDIATE_DEST_FRAMEBUFFER_NEEDED,
381                       needs_readable_framebuffer);
382
383        self.render_targets.clear();
384    }
385
386    pub fn draw_debug_ui(&self) {
387        self.debug_ui_presenter.draw(&self.device);
388    }
389
390    pub fn shift_rendering_time(&mut self) -> Option<RenderTime> {
391        if let Some(pending_timer) = self.pending_timers.pop_front() {
392            if let Some(gpu_time) =
393                    self.device.try_recv_timer_query(&pending_timer.gpu_timer_query) {
394                self.free_timer_queries.push(pending_timer.gpu_timer_query);
395                return Some(RenderTime { gpu_time });
396            }
397            self.pending_timers.push_front(pending_timer);
398        }
399        None
400    }
401
402    #[inline]
403    pub fn dest_framebuffer(&self) -> &DestFramebuffer<D> {
404        &self.dest_framebuffer
405    }
406
407    #[inline]
408    pub fn replace_dest_framebuffer(
409        &mut self,
410        new_dest_framebuffer: DestFramebuffer<D>,
411    ) -> DestFramebuffer<D> {
412        mem::replace(&mut self.dest_framebuffer, new_dest_framebuffer)
413    }
414
415    #[inline]
416    pub fn set_options(&mut self, new_options: RendererOptions) {
417        self.options = new_options
418    }
419
420    #[inline]
421    pub fn set_main_framebuffer_size(&mut self, new_framebuffer_size: Vector2I) {
422        self.debug_ui_presenter.ui_presenter.set_framebuffer_size(new_framebuffer_size);
423    }
424
425    #[inline]
426    pub fn disable_depth(&mut self) {
427        self.flags.remove(RendererFlags::USE_DEPTH);
428    }
429
430    #[inline]
431    pub fn enable_depth(&mut self) {
432        self.flags.insert(RendererFlags::USE_DEPTH);
433    }
434
435    #[inline]
436    pub fn quad_vertex_positions_buffer(&self) -> &D::Buffer {
437        &self.quad_vertex_positions_buffer
438    }
439
440    #[inline]
441    pub fn quad_vertex_indices_buffer(&self) -> &D::Buffer {
442        &self.quad_vertex_indices_buffer
443    }
444
445    fn allocate_texture_page(&mut self,
446                             page_id: TexturePageId,
447                             descriptor: &TexturePageDescriptor) {
448        // Fill in IDs up to the requested page ID.
449        let page_index = page_id.0 as usize;
450        while self.texture_pages.len() < page_index + 1 {
451            self.texture_pages.push(None);
452        }
453
454        // Clear out any existing texture.
455        if let Some(old_texture_page) = self.texture_pages[page_index].take() {
456            let old_texture = self.device.destroy_framebuffer(old_texture_page.framebuffer);
457            self.texture_cache.release_texture(old_texture);
458        }
459
460        // Allocate texture.
461        let texture_size = descriptor.size;
462        let texture = self.texture_cache.create_texture(&mut self.device,
463                                                        TextureFormat::RGBA8,
464                                                        texture_size);
465        let framebuffer = self.device.create_framebuffer(texture);
466        self.texture_pages[page_index] = Some(TexturePage {
467            framebuffer,
468            must_preserve_contents: false,
469        });
470    }
471
472    fn upload_texel_data(&mut self, texels: &[ColorU], location: TextureLocation) {
473        let texture_page = self.texture_pages[location.page.0 as usize]
474                               .as_mut()
475                               .expect("Texture page not allocated yet!");
476        let texture = self.device.framebuffer_texture(&texture_page.framebuffer);
477        let texels = color::color_slice_to_u8_slice(texels);
478        self.device.upload_to_texture(texture, location.rect, TextureDataRef::U8(texels));
479        texture_page.must_preserve_contents = true;
480    }
481
482    fn declare_render_target(&mut self,
483                             render_target_id: RenderTargetId,
484                             location: TextureLocation) {
485        while self.render_targets.len() < render_target_id.render_target as usize + 1 {
486            self.render_targets.push(RenderTargetInfo {
487                location: TextureLocation { page: TexturePageId(!0), rect: RectI::default() },
488            });
489        }
490        let mut render_target = &mut self.render_targets[render_target_id.render_target as usize];
491        debug_assert_eq!(render_target.location.page, TexturePageId(!0));
492        render_target.location = location;
493    }
494
495    fn upload_texture_metadata(&mut self, metadata: &[TextureMetadataEntry]) {
496        let padded_texel_size =
497            (util::alignup_i32(metadata.len() as i32, TEXTURE_METADATA_ENTRIES_PER_ROW) *
498             TEXTURE_METADATA_TEXTURE_WIDTH * 4) as usize;
499        let mut texels = Vec::with_capacity(padded_texel_size);
500        for entry in metadata {
501            let base_color = entry.base_color.to_f32();
502            texels.extend_from_slice(&[
503                f16::from_f32(entry.color_0_transform.m11()),
504                f16::from_f32(entry.color_0_transform.m21()),
505                f16::from_f32(entry.color_0_transform.m12()),
506                f16::from_f32(entry.color_0_transform.m22()),
507                f16::from_f32(entry.color_0_transform.m31()),
508                f16::from_f32(entry.color_0_transform.m32()),
509                f16::default(),
510                f16::default(),
511                f16::from_f32(base_color.r()),
512                f16::from_f32(base_color.g()),
513                f16::from_f32(base_color.b()),
514                f16::from_f32(base_color.a()),
515                f16::default(),
516                f16::default(),
517                f16::default(),
518                f16::default(),
519            ]);
520        }
521        while texels.len() < padded_texel_size {
522            texels.push(f16::default())
523        }
524
525        let texture = &mut self.texture_metadata_texture;
526        let width = TEXTURE_METADATA_TEXTURE_WIDTH;
527        let height = texels.len() as i32 / (4 * TEXTURE_METADATA_TEXTURE_WIDTH);
528        let rect = RectI::new(Vector2I::zero(), Vector2I::new(width, height));
529        self.device.upload_to_texture(texture, rect, TextureDataRef::F16(&texels));
530    }
531
532    fn upload_tiles(&mut self, tiles: &[Tile]) {
533        self.device.allocate_buffer(&self.tile_vertex_buffer,
534                                    BufferData::Memory(&tiles),
535                                    BufferTarget::Vertex,
536                                    BufferUploadMode::Dynamic);
537        self.ensure_index_buffer(tiles.len());
538    }
539
540    fn ensure_index_buffer(&mut self, mut length: usize) {
541        length = length.next_power_of_two();
542        if self.quads_vertex_indices_length >= length {
543            return;
544        }
545
546        // TODO(pcwalton): Generate these with SIMD.
547        let mut indices: Vec<u32> = Vec::with_capacity(length * 6);
548        for index in 0..(length as u32) {
549            indices.extend_from_slice(&[
550                index * 4 + 0, index * 4 + 1, index * 4 + 2,
551                index * 4 + 1, index * 4 + 3, index * 4 + 2,
552            ]);
553        }
554
555        self.device.allocate_buffer(
556            &self.quads_vertex_indices_buffer,
557            BufferData::Memory(&indices),
558            BufferTarget::Index,
559            BufferUploadMode::Static,
560        );
561
562        self.quads_vertex_indices_length = length;
563    }
564
565    fn add_fills(&mut self, fill_batch: &[FillBatchEntry]) {
566        if fill_batch.is_empty() {
567            return;
568        }
569
570        self.stats.fill_count += fill_batch.len();
571
572        for fill_batch_entry in fill_batch {
573            let page = fill_batch_entry.page;
574            while self.alpha_tile_pages.len() <= page as usize {
575                self.alpha_tile_pages.push(AlphaTilePage::new(&mut self.device));
576            }
577            self.alpha_tile_pages[page as usize].buffered_fills.push(fill_batch_entry.fill);
578            if self.alpha_tile_pages[page as usize].buffered_fills.len() == MAX_FILLS_PER_BATCH {
579                self.draw_buffered_fills(page);
580            }
581        }
582    }
583
584    fn draw_buffered_fills(&mut self, page: u16) {
585        let mask_viewport = self.mask_viewport();
586
587        let alpha_tile_page = &mut self.alpha_tile_pages[page as usize];
588        let buffered_fills = &mut alpha_tile_page.buffered_fills;
589        if buffered_fills.is_empty() {
590            return;
591        }
592
593        self.device.allocate_buffer(
594            &self.fill_vertex_array.vertex_buffer,
595            BufferData::Memory(&buffered_fills),
596            BufferTarget::Vertex,
597            BufferUploadMode::Dynamic,
598        );
599
600        let mut clear_color = None;
601        if !alpha_tile_page.must_preserve_framebuffer {
602            clear_color = Some(ColorF::default());
603        };
604
605        debug_assert!(buffered_fills.len() <= u32::MAX as usize);
606        self.device.draw_elements_instanced(6, buffered_fills.len() as u32, &RenderState {
607            target: &RenderTarget::Framebuffer(&alpha_tile_page.framebuffer),
608            program: &self.fill_program.program,
609            vertex_array: &self.fill_vertex_array.vertex_array,
610            primitive: Primitive::Triangles,
611            textures: &[&self.area_lut_texture],
612            uniforms: &[
613                (&self.fill_program.framebuffer_size_uniform,
614                 UniformData::Vec2(F32x2::new(MASK_FRAMEBUFFER_WIDTH as f32,
615                                              MASK_FRAMEBUFFER_HEIGHT as f32))),
616                (&self.fill_program.tile_size_uniform,
617                 UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
618                (&self.fill_program.area_lut_uniform, UniformData::TextureUnit(0)),
619            ],
620            viewport: mask_viewport,
621            options: RenderOptions {
622                blend: Some(BlendState {
623                    src_rgb_factor: BlendFactor::One,
624                    src_alpha_factor: BlendFactor::One,
625                    dest_rgb_factor: BlendFactor::One,
626                    dest_alpha_factor: BlendFactor::One,
627                    ..BlendState::default()
628                }),
629                clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
630                ..RenderOptions::default()
631            },
632        });
633
634        alpha_tile_page.must_preserve_framebuffer = true;
635        buffered_fills.clear();
636    }
637
638    fn tile_transform(&self) -> Transform4F {
639        let draw_viewport = self.draw_viewport().size().to_f32();
640        let scale = Vector4F::new(2.0 / draw_viewport.x(), -2.0 / draw_viewport.y(), 1.0, 1.0);
641        Transform4F::from_scale(scale).translate(Vector4F::new(-1.0, 1.0, 0.0, 1.0))
642    }
643
644    fn draw_tiles(&mut self,
645                  tile_page: u16,
646                  tile_count: u32,
647                  color_texture_0: Option<TileBatchTexture>,
648                  mask_0_fill_rule: Option<FillRule>,
649                  mask_1_fill_rule: Option<FillRule>,
650                  blend_mode: BlendMode,
651                  filter: Filter) {
652        // TODO(pcwalton): Disable blend for solid tiles.
653
654        let needs_readable_framebuffer = blend_mode.needs_readable_framebuffer();
655        if needs_readable_framebuffer {
656            self.copy_alpha_tiles_to_dest_blend_texture(tile_count);
657        }
658
659        let clear_color = self.clear_color_for_draw_operation();
660        let draw_viewport = self.draw_viewport();
661
662        let mut ctrl = 0;
663        for &(fill_rule, shift) in &[
664            (mask_0_fill_rule, COMBINER_CTRL_MASK_0_SHIFT),
665            (mask_1_fill_rule, COMBINER_CTRL_MASK_1_SHIFT),
666        ] {
667            match fill_rule {
668                None => {}
669                Some(FillRule::Winding) => ctrl |= COMBINER_CTRL_MASK_WINDING << shift,
670                Some(FillRule::EvenOdd) => ctrl |= COMBINER_CTRL_MASK_EVEN_ODD << shift,
671            }
672        }
673
674        let mut textures = vec![&self.texture_metadata_texture];
675        let mut uniforms = vec![
676            (&self.tile_program.transform_uniform,
677             UniformData::Mat4(self.tile_transform().to_columns())),
678            (&self.tile_program.tile_size_uniform,
679             UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
680            (&self.tile_program.framebuffer_size_uniform,
681             UniformData::Vec2(draw_viewport.size().to_f32().0)),
682            (&self.tile_program.texture_metadata_uniform, UniformData::TextureUnit(0)),
683            (&self.tile_program.texture_metadata_size_uniform,
684             UniformData::IVec2(I32x2::new(TEXTURE_METADATA_TEXTURE_WIDTH,
685                                           TEXTURE_METADATA_TEXTURE_HEIGHT))),
686        ];
687
688        if needs_readable_framebuffer {
689            uniforms.push((&self.tile_program.dest_texture_uniform,
690                           UniformData::TextureUnit(textures.len() as u32)));
691            textures.push(self.device.framebuffer_texture(&self.dest_blend_framebuffer));
692        }
693
694        if mask_0_fill_rule.is_some() {
695            uniforms.push((&self.tile_program.mask_texture_0_uniform,
696                           UniformData::TextureUnit(textures.len() as u32)));
697            textures.push(self.device.framebuffer_texture(
698                &self.alpha_tile_pages[tile_page as usize].framebuffer));
699        }
700        if mask_1_fill_rule.is_some() {
701            uniforms.push((&self.tile_program.mask_texture_1_uniform,
702                           UniformData::TextureUnit(textures.len() as u32)));
703            textures.push(self.device.framebuffer_texture(
704                &self.alpha_tile_pages[tile_page as usize].framebuffer));
705        }
706
707        // TODO(pcwalton): Refactor.
708        if let Some(color_texture) = color_texture_0 {
709            let color_texture_page = self.texture_page(color_texture.page);
710            let color_texture_size = self.device.texture_size(color_texture_page).to_f32();
711            self.device.set_texture_sampling_mode(color_texture_page,
712                                                  color_texture.sampling_flags);
713            uniforms.push((&self.tile_program.color_texture_0_uniform,
714                           UniformData::TextureUnit(textures.len() as u32)));
715            uniforms.push((&self.tile_program.color_texture_0_size_uniform,
716                           UniformData::Vec2(color_texture_size.0)));
717            textures.push(color_texture_page);
718
719            ctrl |= color_texture.composite_op.to_combine_mode() <<
720                COMBINER_CTRL_COLOR_COMBINE_SHIFT;
721        }
722
723        ctrl |= blend_mode.to_composite_ctrl() << COMBINER_CTRL_COMPOSITE_SHIFT;
724
725        match filter {
726            Filter::None => {}
727            Filter::RadialGradient { line, radii, uv_origin } => {
728                ctrl |= COMBINER_CTRL_FILTER_RADIAL_GRADIENT << COMBINER_CTRL_COLOR_FILTER_SHIFT;
729                self.set_uniforms_for_radial_gradient_filter(&mut uniforms, line, radii, uv_origin)
730            }
731            Filter::PatternFilter(PatternFilter::Text {
732                fg_color,
733                bg_color,
734                defringing_kernel,
735                gamma_correction,
736            }) => {
737                ctrl |= COMBINER_CTRL_FILTER_TEXT << COMBINER_CTRL_COLOR_FILTER_SHIFT;
738                self.set_uniforms_for_text_filter(&mut textures,
739                                                  &mut uniforms,
740                                                  fg_color,
741                                                  bg_color,
742                                                  defringing_kernel,
743                                                  gamma_correction);
744            }
745            Filter::PatternFilter(PatternFilter::Blur { direction, sigma }) => {
746                ctrl |= COMBINER_CTRL_FILTER_BLUR << COMBINER_CTRL_COLOR_FILTER_SHIFT;
747                self.set_uniforms_for_blur_filter(&mut uniforms, direction, sigma);
748            }
749        }
750
751        uniforms.push((&self.tile_program.ctrl_uniform, UniformData::Int(ctrl)));
752
753        self.device.draw_elements_instanced(6, tile_count, &RenderState {
754            target: &self.draw_render_target(),
755            program: &self.tile_program.program,
756            vertex_array: &self.tile_vertex_array.vertex_array,
757            primitive: Primitive::Triangles,
758            textures: &textures,
759            uniforms: &uniforms,
760            viewport: draw_viewport,
761            options: RenderOptions {
762                blend: blend_mode.to_blend_state(),
763                stencil: self.stencil_state(),
764                clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
765                ..RenderOptions::default()
766            },
767        });
768
769        self.preserve_draw_framebuffer();
770    }
771
772    fn copy_alpha_tiles_to_dest_blend_texture(&mut self, tile_count: u32) {
773        let draw_viewport = self.draw_viewport();
774
775        let mut textures = vec![];
776        let mut uniforms = vec![
777            (&self.tile_copy_program.transform_uniform,
778             UniformData::Mat4(self.tile_transform().to_columns())),
779            (&self.tile_copy_program.tile_size_uniform,
780             UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
781        ];
782
783        let draw_framebuffer = match self.draw_render_target() {
784            RenderTarget::Framebuffer(framebuffer) => framebuffer,
785            RenderTarget::Default => panic!("Can't copy alpha tiles from default framebuffer!"),
786        };
787        let draw_texture = self.device.framebuffer_texture(&draw_framebuffer);
788
789        uniforms.push((&self.tile_copy_program.src_uniform,
790                       UniformData::TextureUnit(textures.len() as u32)));
791        textures.push(draw_texture);
792        uniforms.push((&self.tile_copy_program.framebuffer_size_uniform,
793                       UniformData::Vec2(draw_viewport.size().to_f32().0)));
794
795        self.device.draw_elements(tile_count * 6, &RenderState {
796            target: &RenderTarget::Framebuffer(&self.dest_blend_framebuffer),
797            program: &self.tile_copy_program.program,
798            vertex_array: &self.tile_copy_vertex_array.vertex_array,
799            primitive: Primitive::Triangles,
800            textures: &textures,
801            uniforms: &uniforms,
802            viewport: draw_viewport,
803            options: RenderOptions {
804                clear_ops: ClearOps {
805                    color: Some(ColorF::new(1.0, 0.0, 0.0, 1.0)),
806                    ..ClearOps::default()
807                },
808                ..RenderOptions::default()
809            },
810        });
811    }
812
813    fn draw_stencil(&mut self, quad_positions: &[Vector4F]) {
814        self.device.allocate_buffer(
815            &self.stencil_vertex_array.vertex_buffer,
816            BufferData::Memory(quad_positions),
817            BufferTarget::Vertex,
818            BufferUploadMode::Dynamic,
819        );
820
821        // Create indices for a triangle fan. (This is OK because the clipped quad should always be
822        // convex.)
823        let mut indices: Vec<u32> = vec![];
824        for index in 1..(quad_positions.len() as u32 - 1) {
825            indices.extend_from_slice(&[0, index as u32, index + 1]);
826        }
827        self.device.allocate_buffer(
828            &self.stencil_vertex_array.index_buffer,
829            BufferData::Memory(&indices),
830            BufferTarget::Index,
831            BufferUploadMode::Dynamic,
832        );
833
834        self.device.draw_elements(indices.len() as u32, &RenderState {
835            target: &self.draw_render_target(),
836            program: &self.stencil_program.program,
837            vertex_array: &self.stencil_vertex_array.vertex_array,
838            primitive: Primitive::Triangles,
839            textures: &[],
840            uniforms: &[],
841            viewport: self.draw_viewport(),
842            options: RenderOptions {
843                // FIXME(pcwalton): Should we really write to the depth buffer?
844                depth: Some(DepthState { func: DepthFunc::Less, write: true }),
845                stencil: Some(StencilState {
846                    func: StencilFunc::Always,
847                    reference: 1,
848                    mask: 1,
849                    write: true,
850                }),
851                color_mask: false,
852                clear_ops: ClearOps { stencil: Some(0), ..ClearOps::default() },
853                ..RenderOptions::default()
854            },
855        });
856    }
857
858    pub fn reproject_texture(
859        &mut self,
860        texture: &D::Texture,
861        old_transform: &Transform4F,
862        new_transform: &Transform4F,
863    ) {
864        let clear_color = self.clear_color_for_draw_operation();
865
866        self.device.draw_elements(6, &RenderState {
867            target: &self.draw_render_target(),
868            program: &self.reprojection_program.program,
869            vertex_array: &self.reprojection_vertex_array.vertex_array,
870            primitive: Primitive::Triangles,
871            textures: &[texture],
872            uniforms: &[
873                (&self.reprojection_program.old_transform_uniform,
874                 UniformData::from_transform_3d(old_transform)),
875                (&self.reprojection_program.new_transform_uniform,
876                 UniformData::from_transform_3d(new_transform)),
877                (&self.reprojection_program.texture_uniform, UniformData::TextureUnit(0)),
878            ],
879            viewport: self.draw_viewport(),
880            options: RenderOptions {
881                blend: BlendMode::SrcOver.to_blend_state(),
882                depth: Some(DepthState { func: DepthFunc::Less, write: false, }),
883                clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
884                ..RenderOptions::default()
885            },
886        });
887
888        self.preserve_draw_framebuffer();
889    }
890
891    pub fn draw_render_target(&self) -> RenderTarget<D> {
892        match self.render_target_stack.last() {
893            Some(&render_target_id) => {
894                let texture_page_id = self.render_target_location(render_target_id).page;
895                let framebuffer = self.texture_page_framebuffer(texture_page_id);
896                RenderTarget::Framebuffer(framebuffer)
897            }
898            None => {
899                if self.flags.contains(RendererFlags::INTERMEDIATE_DEST_FRAMEBUFFER_NEEDED) {
900                    RenderTarget::Framebuffer(&self.intermediate_dest_framebuffer)
901                } else {
902                    match self.dest_framebuffer {
903                        DestFramebuffer::Default { .. } => RenderTarget::Default,
904                        DestFramebuffer::Other(ref framebuffer) => {
905                            RenderTarget::Framebuffer(framebuffer)
906                        }
907                    }
908                }
909            }
910        }
911    }
912
913    fn push_render_target(&mut self, render_target_id: RenderTargetId) {
914        self.render_target_stack.push(render_target_id);
915    }
916
917    fn pop_render_target(&mut self) {
918        self.render_target_stack.pop().expect("Render target stack underflow!");
919    }
920
921    fn set_uniforms_for_radial_gradient_filter<'a>(
922            &'a self,
923            uniforms: &mut Vec<(&'a D::Uniform, UniformData)>,
924            line: LineSegment2F,
925            radii: F32x2,
926            uv_origin: Vector2F) {
927        uniforms.extend_from_slice(&[
928            (&self.tile_program.filter_params_0_uniform,
929             UniformData::Vec4(line.from().0.concat_xy_xy(line.vector().0))),
930            (&self.tile_program.filter_params_1_uniform,
931             UniformData::Vec4(radii.concat_xy_xy(uv_origin.0))),
932        ]);
933    }
934
935    fn set_uniforms_for_text_filter<'a>(&'a self,
936                                        textures: &mut Vec<&'a D::Texture>,
937                                        uniforms: &mut Vec<(&'a D::Uniform, UniformData)>,
938                                        fg_color: ColorF,
939                                        bg_color: ColorF,
940                                        defringing_kernel: Option<DefringingKernel>,
941                                        gamma_correction: bool) {
942        let gamma_lut_texture_unit = textures.len() as u32;
943        textures.push(&self.gamma_lut_texture);
944
945        match defringing_kernel {
946            Some(ref kernel) => {
947                uniforms.push((&self.tile_program.filter_params_0_uniform,
948                               UniformData::Vec4(F32x4::from_slice(&kernel.0))));
949            }
950            None => {
951                uniforms.push((&self.tile_program.filter_params_0_uniform,
952                               UniformData::Vec4(F32x4::default())));
953            }
954        }
955
956        let mut params_2 = fg_color.0;
957        params_2.set_w(gamma_correction as i32 as f32);
958
959        uniforms.extend_from_slice(&[
960            (&self.tile_program.gamma_lut_uniform,
961             UniformData::TextureUnit(gamma_lut_texture_unit)),
962            (&self.tile_program.filter_params_1_uniform, UniformData::Vec4(bg_color.0)),
963            (&self.tile_program.filter_params_2_uniform, UniformData::Vec4(params_2)),
964        ]);
965
966    }
967
968    fn set_uniforms_for_blur_filter<'a>(&'a self,
969                                        uniforms: &mut Vec<(&'a D::Uniform, UniformData)>,
970                                        direction: BlurDirection,
971                                        sigma: f32) {
972        let sigma_inv = 1.0 / sigma;
973        let gauss_coeff_x = SQRT_2_PI_INV * sigma_inv;
974        let gauss_coeff_y = f32::exp(-0.5 * sigma_inv * sigma_inv);
975        let gauss_coeff_z = gauss_coeff_y * gauss_coeff_y;
976
977        let src_offset = match direction {
978            BlurDirection::X => vec2f(1.0, 0.0),
979            BlurDirection::Y => vec2f(0.0, 1.0),
980        };
981
982        let support = f32::ceil(1.5 * sigma) * 2.0;
983
984        uniforms.extend_from_slice(&[
985            (&self.tile_program.filter_params_0_uniform,
986             UniformData::Vec4(src_offset.0.concat_xy_xy(F32x2::new(support, 0.0)))),
987            (&self.tile_program.filter_params_1_uniform,
988             UniformData::Vec4(F32x4::new(gauss_coeff_x, gauss_coeff_y, gauss_coeff_z, 0.0))),
989        ]);
990    }
991
992    fn blit_intermediate_dest_framebuffer_if_necessary(&mut self) {
993        if !self.flags.contains(RendererFlags::INTERMEDIATE_DEST_FRAMEBUFFER_NEEDED) {
994            return;
995        }
996
997        let main_viewport = self.main_viewport();
998
999        let uniforms = [(&self.blit_program.src_uniform, UniformData::TextureUnit(0))];
1000        let textures = [(self.device.framebuffer_texture(&self.intermediate_dest_framebuffer))];
1001
1002        self.device.draw_elements(6, &RenderState {
1003            target: &RenderTarget::Default,
1004            program: &self.blit_program.program,
1005            vertex_array: &self.blit_vertex_array.vertex_array,
1006            primitive: Primitive::Triangles,
1007            textures: &textures[..],
1008            uniforms: &uniforms[..],
1009            viewport: main_viewport,
1010            options: RenderOptions {
1011                clear_ops: ClearOps {
1012                    color: Some(ColorF::new(0.0, 0.0, 0.0, 1.0)),
1013                    ..ClearOps::default()
1014                },
1015                ..RenderOptions::default()
1016            },
1017        });
1018    }
1019
1020    fn stencil_state(&self) -> Option<StencilState> {
1021        if !self.flags.contains(RendererFlags::USE_DEPTH) {
1022            return None;
1023        }
1024
1025        Some(StencilState {
1026            func: StencilFunc::Equal,
1027            reference: 1,
1028            mask: 1,
1029            write: false,
1030        })
1031    }
1032
1033    fn clear_color_for_draw_operation(&self) -> Option<ColorF> {
1034        let must_preserve_contents = match self.render_target_stack.last() {
1035            Some(&render_target_id) => {
1036                let texture_page = self.render_target_location(render_target_id).page;
1037                self.texture_pages[texture_page.0 as usize]
1038                    .as_ref()
1039                    .expect("Draw target texture page not allocated!")
1040                    .must_preserve_contents
1041            }
1042            None => {
1043                self.framebuffer_flags
1044                    .contains(FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS)
1045            }
1046        };
1047
1048        if must_preserve_contents {
1049            None
1050        } else if self.render_target_stack.is_empty() {
1051            self.options.background_color
1052        } else {
1053            Some(ColorF::default())
1054        }
1055    }
1056
1057    fn preserve_draw_framebuffer(&mut self) {
1058        match self.render_target_stack.last() {
1059            Some(&render_target_id) => {
1060                let texture_page = self.render_target_location(render_target_id).page;
1061                self.texture_pages[texture_page.0 as usize]
1062                    .as_mut()
1063                    .expect("Draw target texture page not allocated!")
1064                    .must_preserve_contents = true;
1065            }
1066            None => {
1067                self.framebuffer_flags
1068                    .insert(FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS);
1069            }
1070        }
1071    }
1072
1073    pub fn draw_viewport(&self) -> RectI {
1074        match self.render_target_stack.last() {
1075            Some(&render_target_id) => self.render_target_location(render_target_id).rect,
1076            None => self.main_viewport(),
1077        }
1078    }
1079
1080    fn main_viewport(&self) -> RectI {
1081        match self.dest_framebuffer {
1082            DestFramebuffer::Default { viewport, .. } => viewport,
1083            DestFramebuffer::Other(ref framebuffer) => {
1084                let size = self
1085                    .device
1086                    .texture_size(self.device.framebuffer_texture(framebuffer));
1087                RectI::new(Vector2I::default(), size)
1088            }
1089        }
1090    }
1091
1092    fn mask_viewport(&self) -> RectI {
1093        RectI::new(Vector2I::zero(), vec2i(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT))
1094    }
1095
1096    fn render_target_location(&self, render_target_id: RenderTargetId) -> TextureLocation {
1097        self.render_targets[render_target_id.render_target as usize].location
1098    }
1099
1100    fn texture_page_framebuffer(&self, id: TexturePageId) -> &D::Framebuffer {
1101        &self.texture_pages[id.0 as usize]
1102             .as_ref()
1103             .expect("Texture page not allocated!")
1104             .framebuffer
1105    }
1106
1107    fn texture_page(&self, id: TexturePageId) -> &D::Texture {
1108        self.device.framebuffer_texture(&self.texture_page_framebuffer(id))
1109    }
1110
1111    fn allocate_timer_query(&mut self) -> Option<D::TimerQuery> {
1112        self.free_timer_queries.pop()
1113    }
1114}
1115
1116// Render stats
1117
1118#[derive(Clone, Copy, Debug, Default)]
1119pub struct RenderStats {
1120    pub path_count: usize,
1121    pub fill_count: usize,
1122    pub alpha_tile_count: usize,
1123    pub solid_tile_count: usize,
1124    pub cpu_build_time: Duration,
1125}
1126
1127impl Add<RenderStats> for RenderStats {
1128    type Output = RenderStats;
1129    fn add(self, other: RenderStats) -> RenderStats {
1130        RenderStats {
1131            path_count: self.path_count + other.path_count,
1132            solid_tile_count: self.solid_tile_count + other.solid_tile_count,
1133            alpha_tile_count: self.alpha_tile_count + other.alpha_tile_count,
1134            fill_count: self.fill_count + other.fill_count,
1135            cpu_build_time: self.cpu_build_time + other.cpu_build_time,
1136        }
1137    }
1138}
1139
1140impl Div<usize> for RenderStats {
1141    type Output = RenderStats;
1142    fn div(self, divisor: usize) -> RenderStats {
1143        RenderStats {
1144            path_count: self.path_count / divisor,
1145            solid_tile_count: self.solid_tile_count / divisor,
1146            alpha_tile_count: self.alpha_tile_count / divisor,
1147            fill_count: self.fill_count / divisor,
1148            cpu_build_time: self.cpu_build_time / divisor as u32,
1149        }
1150    }
1151}
1152
1153#[derive(Clone, Copy, Debug)]
1154struct PendingTimer<D> where D: Device {
1155    gpu_timer_query: D::TimerQuery,
1156}
1157
1158#[derive(Clone, Copy, Debug)]
1159pub struct RenderTime {
1160    pub gpu_time: Duration,
1161}
1162
1163impl Default for RenderTime {
1164    #[inline]
1165    fn default() -> RenderTime {
1166        RenderTime { gpu_time: Duration::new(0, 0) }
1167    }
1168}
1169
1170impl Add<RenderTime> for RenderTime {
1171    type Output = RenderTime;
1172
1173    #[inline]
1174    fn add(self, other: RenderTime) -> RenderTime {
1175        RenderTime { gpu_time: self.gpu_time + other.gpu_time }
1176    }
1177}
1178
1179impl Div<usize> for RenderTime {
1180    type Output = RenderTime;
1181
1182    #[inline]
1183    fn div(self, divisor: usize) -> RenderTime {
1184        RenderTime { gpu_time: self.gpu_time / divisor as u32 }
1185    }
1186}
1187
1188bitflags! {
1189    struct FramebufferFlags: u8 {
1190        const MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS = 0x01;
1191        const MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS = 0x02;
1192    }
1193}
1194
1195struct TextureCache<D> where D: Device {
1196    textures: Vec<D::Texture>,
1197}
1198
1199impl<D> TextureCache<D> where D: Device {
1200    fn new() -> TextureCache<D> {
1201        TextureCache { textures: vec![] }
1202    }
1203
1204    fn create_texture(&mut self, device: &mut D, format: TextureFormat, size: Vector2I)
1205                      -> D::Texture {
1206        for index in 0..self.textures.len() {
1207            if device.texture_size(&self.textures[index]) == size &&
1208                    device.texture_format(&self.textures[index]) == format {
1209                return self.textures.remove(index);
1210            }
1211        }
1212
1213        device.create_texture(format, size)
1214    }
1215
1216    fn release_texture(&mut self, texture: D::Texture) {
1217        if self.textures.len() == TEXTURE_CACHE_SIZE {
1218            self.textures.pop();
1219        }
1220        self.textures.insert(0, texture);
1221    }
1222}
1223
1224struct TexturePage<D> where D: Device {
1225    framebuffer: D::Framebuffer,
1226    must_preserve_contents: bool,
1227}
1228
1229struct RenderTargetInfo {
1230    location: TextureLocation,
1231}
1232
1233trait ToBlendState {
1234    fn to_blend_state(self) -> Option<BlendState>;
1235}
1236
1237impl ToBlendState for BlendMode {
1238    fn to_blend_state(self) -> Option<BlendState> {
1239        match self {
1240            BlendMode::Clear => {
1241                Some(BlendState {
1242                    src_rgb_factor: BlendFactor::Zero,
1243                    dest_rgb_factor: BlendFactor::Zero,
1244                    src_alpha_factor: BlendFactor::Zero,
1245                    dest_alpha_factor: BlendFactor::Zero,
1246                    ..BlendState::default()
1247                })
1248            }
1249            BlendMode::SrcOver => {
1250                Some(BlendState {
1251                    src_rgb_factor: BlendFactor::One,
1252                    dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
1253                    src_alpha_factor: BlendFactor::One,
1254                    dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
1255                    ..BlendState::default()
1256                })
1257            }
1258            BlendMode::DestOver => {
1259                Some(BlendState {
1260                    src_rgb_factor: BlendFactor::OneMinusDestAlpha,
1261                    dest_rgb_factor: BlendFactor::One,
1262                    src_alpha_factor: BlendFactor::OneMinusDestAlpha,
1263                    dest_alpha_factor: BlendFactor::One,
1264                    ..BlendState::default()
1265                })
1266            }
1267            BlendMode::SrcIn => {
1268                Some(BlendState {
1269                    src_rgb_factor: BlendFactor::DestAlpha,
1270                    dest_rgb_factor: BlendFactor::Zero,
1271                    src_alpha_factor: BlendFactor::DestAlpha,
1272                    dest_alpha_factor: BlendFactor::Zero,
1273                    ..BlendState::default()
1274                })
1275            }
1276            BlendMode::DestIn => {
1277                Some(BlendState {
1278                    src_rgb_factor: BlendFactor::Zero,
1279                    dest_rgb_factor: BlendFactor::SrcAlpha,
1280                    src_alpha_factor: BlendFactor::Zero,
1281                    dest_alpha_factor: BlendFactor::SrcAlpha,
1282                    ..BlendState::default()
1283                })
1284            }
1285            BlendMode::SrcOut => {
1286                Some(BlendState {
1287                    src_rgb_factor: BlendFactor::OneMinusDestAlpha,
1288                    dest_rgb_factor: BlendFactor::Zero,
1289                    src_alpha_factor: BlendFactor::OneMinusDestAlpha,
1290                    dest_alpha_factor: BlendFactor::Zero,
1291                    ..BlendState::default()
1292                })
1293            }
1294            BlendMode::DestOut => {
1295                Some(BlendState {
1296                    src_rgb_factor: BlendFactor::Zero,
1297                    dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
1298                    src_alpha_factor: BlendFactor::Zero,
1299                    dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
1300                    ..BlendState::default()
1301                })
1302            }
1303            BlendMode::SrcAtop => {
1304                Some(BlendState {
1305                    src_rgb_factor: BlendFactor::DestAlpha,
1306                    dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
1307                    src_alpha_factor: BlendFactor::DestAlpha,
1308                    dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
1309                    ..BlendState::default()
1310                })
1311            }
1312            BlendMode::DestAtop => {
1313                Some(BlendState {
1314                    src_rgb_factor: BlendFactor::OneMinusDestAlpha,
1315                    dest_rgb_factor: BlendFactor::SrcAlpha,
1316                    src_alpha_factor: BlendFactor::OneMinusDestAlpha,
1317                    dest_alpha_factor: BlendFactor::SrcAlpha,
1318                    ..BlendState::default()
1319                })
1320            }
1321            BlendMode::Xor => {
1322                Some(BlendState {
1323                    src_rgb_factor: BlendFactor::OneMinusDestAlpha,
1324                    dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
1325                    src_alpha_factor: BlendFactor::OneMinusDestAlpha,
1326                    dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
1327                    ..BlendState::default()
1328                })
1329            }
1330            BlendMode::Lighter => {
1331                Some(BlendState {
1332                    src_rgb_factor: BlendFactor::One,
1333                    dest_rgb_factor: BlendFactor::One,
1334                    src_alpha_factor: BlendFactor::One,
1335                    dest_alpha_factor: BlendFactor::One,
1336                    ..BlendState::default()
1337                })
1338            }
1339            BlendMode::Copy |
1340            BlendMode::Darken |
1341            BlendMode::Lighten |
1342            BlendMode::Multiply |
1343            BlendMode::Screen |
1344            BlendMode::HardLight |
1345            BlendMode::Overlay |
1346            BlendMode::ColorDodge |
1347            BlendMode::ColorBurn |
1348            BlendMode::SoftLight |
1349            BlendMode::Difference |
1350            BlendMode::Exclusion |
1351            BlendMode::Hue |
1352            BlendMode::Saturation |
1353            BlendMode::Color |
1354            BlendMode::Luminosity => {
1355                // Blending is done manually in the shader.
1356                None
1357            }
1358        }
1359    }
1360}
1361
1362pub trait BlendModeExt {
1363    fn needs_readable_framebuffer(self) -> bool;
1364}
1365
1366impl BlendModeExt for BlendMode {
1367    fn needs_readable_framebuffer(self) -> bool {
1368        match self {
1369            BlendMode::Clear |
1370            BlendMode::SrcOver |
1371            BlendMode::DestOver |
1372            BlendMode::SrcIn |
1373            BlendMode::DestIn |
1374            BlendMode::SrcOut |
1375            BlendMode::DestOut |
1376            BlendMode::SrcAtop |
1377            BlendMode::DestAtop |
1378            BlendMode::Xor |
1379            BlendMode::Lighter |
1380            BlendMode::Copy => false,
1381            BlendMode::Lighten |
1382            BlendMode::Darken |
1383            BlendMode::Multiply |
1384            BlendMode::Screen |
1385            BlendMode::HardLight |
1386            BlendMode::Overlay |
1387            BlendMode::ColorDodge |
1388            BlendMode::ColorBurn |
1389            BlendMode::SoftLight |
1390            BlendMode::Difference |
1391            BlendMode::Exclusion |
1392            BlendMode::Hue |
1393            BlendMode::Saturation |
1394            BlendMode::Color |
1395            BlendMode::Luminosity => true,
1396        }
1397    }
1398}
1399
1400struct AlphaTilePage<D> where D: Device {
1401    buffered_fills: Vec<Fill>,
1402    framebuffer: D::Framebuffer,
1403    must_preserve_framebuffer: bool,
1404}
1405
1406impl<D> AlphaTilePage<D> where D: Device {
1407    fn new(device: &mut D) -> AlphaTilePage<D> {
1408        let framebuffer_size = vec2i(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT);
1409        let framebuffer_texture = device.create_texture(TextureFormat::R16F, framebuffer_size);
1410        let framebuffer = device.create_framebuffer(framebuffer_texture);
1411        AlphaTilePage { buffered_fills: vec![], framebuffer, must_preserve_framebuffer: false }
1412    }
1413}
1414
1415bitflags! {
1416    struct RendererFlags: u8 {
1417        // Whether we need a depth buffer.
1418        const USE_DEPTH = 0x01;
1419        // Whether an intermediate destination framebuffer is needed.
1420        //
1421        // This will be true if any exotic blend modes are used at the top level (not inside a
1422        // render target), *and* the output framebuffer is the default framebuffer.
1423        const INTERMEDIATE_DEST_FRAMEBUFFER_NEEDED = 0x02;
1424    }
1425}
1426
1427trait ToCompositeCtrl {
1428    fn to_composite_ctrl(&self) -> i32;
1429}
1430
1431impl ToCompositeCtrl for BlendMode {
1432    fn to_composite_ctrl(&self) -> i32 {
1433        match *self {
1434            BlendMode::SrcOver |
1435            BlendMode::SrcAtop |
1436            BlendMode::DestOver |
1437            BlendMode::DestOut |
1438            BlendMode::Xor |
1439            BlendMode::Lighter |
1440            BlendMode::Clear |
1441            BlendMode::Copy |
1442            BlendMode::SrcIn |
1443            BlendMode::SrcOut |
1444            BlendMode::DestIn |
1445            BlendMode::DestAtop => COMBINER_CTRL_COMPOSITE_NORMAL,
1446            BlendMode::Multiply => COMBINER_CTRL_COMPOSITE_MULTIPLY,
1447            BlendMode::Darken => COMBINER_CTRL_COMPOSITE_DARKEN,
1448            BlendMode::Lighten => COMBINER_CTRL_COMPOSITE_LIGHTEN,
1449            BlendMode::Screen => COMBINER_CTRL_COMPOSITE_SCREEN,
1450            BlendMode::Overlay => COMBINER_CTRL_COMPOSITE_OVERLAY,
1451            BlendMode::ColorDodge => COMBINER_CTRL_COMPOSITE_COLOR_DODGE,
1452            BlendMode::ColorBurn => COMBINER_CTRL_COMPOSITE_COLOR_BURN,
1453            BlendMode::HardLight => COMBINER_CTRL_COMPOSITE_HARD_LIGHT,
1454            BlendMode::SoftLight => COMBINER_CTRL_COMPOSITE_SOFT_LIGHT,
1455            BlendMode::Difference => COMBINER_CTRL_COMPOSITE_DIFFERENCE,
1456            BlendMode::Exclusion => COMBINER_CTRL_COMPOSITE_EXCLUSION,
1457            BlendMode::Hue => COMBINER_CTRL_COMPOSITE_HUE,
1458            BlendMode::Saturation => COMBINER_CTRL_COMPOSITE_SATURATION,
1459            BlendMode::Color => COMBINER_CTRL_COMPOSITE_COLOR,
1460            BlendMode::Luminosity => COMBINER_CTRL_COMPOSITE_LUMINOSITY,
1461        }
1462    }
1463}
1464
1465trait ToCombineMode {
1466    fn to_combine_mode(self) -> i32;
1467}
1468
1469impl ToCombineMode for PaintCompositeOp {
1470    fn to_combine_mode(self) -> i32 {
1471        match self {
1472            PaintCompositeOp::DestIn => COMBINER_CTRL_COLOR_COMBINE_DEST_IN,
1473            PaintCompositeOp::SrcIn => COMBINER_CTRL_COLOR_COMBINE_SRC_IN,
1474        }
1475    }
1476}