1use 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
53const 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
63const 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 pub device: D,
106
107 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_program: StencilProgram<D>,
135 stencil_vertex_array: StencilVertexArray<D>,
136
137 reprojection_program: ReprojectionProgram<D>,
139 reprojection_vertex_array: ReprojectionVertexArray<D>,
140
141 framebuffer_flags: FramebufferFlags,
143 texture_cache: TextureCache<D>,
144
145 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 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 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 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 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 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 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 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 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 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#[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 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 const USE_DEPTH = 0x01;
1419 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}