diff --git a/webrender/res/prim_shared.glsl b/webrender/res/prim_shared.glsl index beb9abca5c..d25b715254 100644 --- a/webrender/res/prim_shared.glsl +++ b/webrender/res/prim_shared.glsl @@ -34,6 +34,8 @@ #define MAX_STOPS_PER_ANGLE_GRADIENT 8 +uniform sampler2DArray sCache; + #ifdef WR_VERTEX_SHADER #define VECS_PER_LAYER 13 @@ -121,7 +123,7 @@ Layer fetch_layer(int index) { struct Tile { vec4 screen_origin_task_origin; - vec4 size; + vec4 size_target_index; }; Tile fetch_tile(int index) { @@ -130,7 +132,7 @@ Tile fetch_tile(int index) { ivec2 uv = get_fetch_uv(index, VECS_PER_TILE); tile.screen_origin_task_origin = texelFetchOffset(sRenderTasks, uv, 0, ivec2(0, 0)); - tile.size = texelFetchOffset(sRenderTasks, uv, 0, ivec2(1, 0)); + tile.size_target_index = texelFetchOffset(sRenderTasks, uv, 0, ivec2(1, 0)); return tile; } @@ -425,7 +427,7 @@ VertexInfo write_vertex(vec4 instance_rect, vec2 clamped_pos = clamp(device_pos, vec2(tile.screen_origin_task_origin.xy), - vec2(tile.screen_origin_task_origin.xy + tile.size.xy)); + vec2(tile.screen_origin_task_origin.xy + tile.size_target_index.xy)); vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, world_pos.z, 1); local_clamped_pos.xyz /= local_clamped_pos.w; @@ -479,11 +481,11 @@ TransformVertexInfo write_transform_vertex(vec4 instance_rect, vec2 min_pos_clamped = clamp(min_pos * uDevicePixelRatio, vec2(tile.screen_origin_task_origin.xy), - vec2(tile.screen_origin_task_origin.xy + tile.size.xy)); + vec2(tile.screen_origin_task_origin.xy + tile.size_target_index.xy)); vec2 max_pos_clamped = clamp(max_pos * uDevicePixelRatio, vec2(tile.screen_origin_task_origin.xy), - vec2(tile.screen_origin_task_origin.xy + tile.size.xy)); + vec2(tile.screen_origin_task_origin.xy + tile.size_target_index.xy)); vec2 clamped_pos = mix(min_pos_clamped, max_pos_clamped, diff --git a/webrender/res/ps_blend.fs.glsl b/webrender/res/ps_blend.fs.glsl index 30a8712cc4..7ce203fbbf 100644 --- a/webrender/res/ps_blend.fs.glsl +++ b/webrender/res/ps_blend.fs.glsl @@ -2,8 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -uniform sampler2D sCache; - vec3 rgbToHsv(vec3 c) { float value = max(max(c.r, c.g), c.b); diff --git a/webrender/res/ps_blend.glsl b/webrender/res/ps_blend.glsl index 0531cf06f5..09e6d9262a 100644 --- a/webrender/res/ps_blend.glsl +++ b/webrender/res/ps_blend.glsl @@ -2,6 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -varying vec2 vUv; +varying vec3 vUv; flat varying float vAmount; flat varying int vOp; diff --git a/webrender/res/ps_blend.vs.glsl b/webrender/res/ps_blend.vs.glsl index 93f928aa1c..97a9c6838e 100644 --- a/webrender/res/ps_blend.vs.glsl +++ b/webrender/res/ps_blend.vs.glsl @@ -13,12 +13,13 @@ void main(void) { src.screen_origin_task_origin.xy; vec2 local_pos = mix(dest_origin, - dest_origin + src.size.xy, + dest_origin + src.size_target_index.xy, aPosition.xy); - vec2 st0 = vec2(src.screen_origin_task_origin.zw) / 2048.0; - vec2 st1 = vec2(src.screen_origin_task_origin.zw + src.size.xy) / 2048.0; - vUv = mix(st0, st1, aPosition.xy); + vec2 texture_size = vec2(textureSize(sCache, 0)); + vec2 st0 = src.screen_origin_task_origin.zw / texture_size; + vec2 st1 = (src.screen_origin_task_origin.zw + src.size_target_index.xy) / texture_size; + vUv = vec3(mix(st0, st1, aPosition.xy), src.size_target_index.z); vOp = blend.src_id_target_id_op_amount.z; vAmount = blend.src_id_target_id_op_amount.w / 65535.0; diff --git a/webrender/res/ps_composite.fs.glsl b/webrender/res/ps_composite.fs.glsl index 8d97b91ae4..3b6606c880 100644 --- a/webrender/res/ps_composite.fs.glsl +++ b/webrender/res/ps_composite.fs.glsl @@ -4,8 +4,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -uniform sampler2D sCache; - float gauss(float x, float sigma) { if (sigma == 0.0) return 1.0; diff --git a/webrender/res/ps_composite.glsl b/webrender/res/ps_composite.glsl index cf9fecde52..d2a1310d59 100644 --- a/webrender/res/ps_composite.glsl +++ b/webrender/res/ps_composite.glsl @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -varying vec2 vUv0; -varying vec2 vUv1; +varying vec3 vUv0; +varying vec3 vUv1; flat varying vec4 vUv1Rect; flat varying int vOp; diff --git a/webrender/res/ps_composite.vs.glsl b/webrender/res/ps_composite.vs.glsl index 1789d79e0f..2af03286cc 100644 --- a/webrender/res/ps_composite.vs.glsl +++ b/webrender/res/ps_composite.vs.glsl @@ -10,20 +10,21 @@ void main(void) { Tile dest = fetch_tile(composite.src0_src1_target_id_op.z); vec2 local_pos = mix(dest.screen_origin_task_origin.zw, - dest.screen_origin_task_origin.zw + dest.size.xy, + dest.screen_origin_task_origin.zw + dest.size_target_index.xy, aPosition.xy); - vec2 st0 = vec2(src0.screen_origin_task_origin.zw) / 2048.0; - vec2 st1 = vec2(src0.screen_origin_task_origin.zw + src0.size.xy) / 2048.0; - vUv0 = mix(st0, st1, aPosition.xy); + vec2 texture_size = vec2(textureSize(sCache, 0)); + vec2 st0 = src0.screen_origin_task_origin.zw / texture_size; + vec2 st1 = (src0.screen_origin_task_origin.zw + src0.size_target_index.xy) / texture_size; + vUv0 = vec3(mix(st0, st1, aPosition.xy), src0.size_target_index.z); - st0 = vec2(src1.screen_origin_task_origin.zw) / 2048.0; - st1 = vec2(src1.screen_origin_task_origin.zw + src1.size.xy) / 2048.0; + st0 = vec2(src1.screen_origin_task_origin.zw) / texture_size; + st1 = vec2(src1.screen_origin_task_origin.zw + src1.size_target_index.xy) / texture_size; vec2 local_virtual_pos = mix(dest.screen_origin_task_origin.xy, - dest.screen_origin_task_origin.xy + dest.size.xy, + dest.screen_origin_task_origin.xy + dest.size_target_index.xy, aPosition.xy); - vec2 f = (local_virtual_pos - src1.screen_origin_task_origin.xy) / src1.size.xy; - vUv1 = mix(st0, st1, f); + vec2 f = (local_virtual_pos - src1.screen_origin_task_origin.xy) / src1.size_target_index.xy; + vUv1 = vec3(mix(st0, st1, f), src1.size_target_index.z); vUv1Rect = vec4(st0, st1); vOp = composite.src0_src1_target_id_op.w; diff --git a/webrender/src/debug_render.rs b/webrender/src/debug_render.rs index 6d1d678e7b..1bcce86a17 100644 --- a/webrender/src/debug_render.rs +++ b/webrender/src/debug_render.rs @@ -4,7 +4,7 @@ use debug_font_data; use device::{Device, ProgramId, VAOId, TextureId, VertexFormat}; -use device::{TextureFilter, VertexUsageHint}; +use device::{TextureFilter, VertexUsageHint, TextureTarget}; use euclid::{Matrix4D, Point2D, Size2D, Rect}; use gleam::gl; use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, TextureSampler}; @@ -36,7 +36,7 @@ impl DebugRenderer { let line_vao = device.create_vao(VertexFormat::DebugColor, None); let tri_vao = device.create_vao(VertexFormat::DebugColor, None); - let font_texture_id = device.create_texture_ids(1)[0]; + let font_texture_id = device.create_texture_ids(1, TextureTarget::Default)[0]; device.init_texture(font_texture_id, debug_font_data::BMP_WIDTH, debug_font_data::BMP_HEIGHT, diff --git a/webrender/src/device.rs b/webrender/src/device.rs index c857e01e2c..e54cfc9453 100644 --- a/webrender/src/device.rs +++ b/webrender/src/device.rs @@ -45,6 +45,12 @@ lazy_static! { }; } +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum TextureTarget { + Default, + Array, +} + #[derive(Copy, Clone, Debug, PartialEq)] pub enum TextureFilter { Nearest, @@ -317,12 +323,21 @@ impl VertexFormat { impl TextureId { pub fn bind(&self) { - let TextureId(id) = *self; - gl::bind_texture(gl::TEXTURE_2D, id); + gl::bind_texture(self.target, self.name); + } + + pub fn new(name: gl::GLuint) -> TextureId { + TextureId { + name: name, + target: gl::TEXTURE_2D, + } } pub fn invalid() -> TextureId { - TextureId(0) + TextureId { + name: 0, + target: gl::TEXTURE_2D, + } } } @@ -490,7 +505,10 @@ impl Drop for VAO { } #[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Copy, Clone)] -pub struct TextureId(pub gl::GLuint); // TODO: HACK: Should not be public! +pub struct TextureId { + name: gl::GLuint, + target: gl::GLuint, +} #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] pub struct ProgramId(pub gl::GLuint); @@ -804,7 +822,7 @@ impl Device { device_pixel_ratio: device_pixel_ratio, inside_frame: false, - bound_textures: [ TextureId(0); 16 ], + bound_textures: [ TextureId::invalid(); 16 ], bound_program: ProgramId(0), bound_vao: VAOId(0), bound_fbo: FBOId(0), @@ -866,7 +884,7 @@ impl Device { // Texture state for i in 0..self.bound_textures.len() { - self.bound_textures[i] = TextureId(0); + self.bound_textures[i] = TextureId::invalid(); gl::active_texture(gl::TEXTURE0 + i as gl::GLuint); gl::bind_texture(gl::TEXTURE_2D, 0); } @@ -889,7 +907,9 @@ impl Device { gl::active_texture(gl::TEXTURE0); } - pub fn bind_texture(&mut self, sampler: TextureSampler, texture_id: TextureId) { + pub fn bind_texture(&mut self, + sampler: TextureSampler, + texture_id: TextureId) { debug_assert!(self.inside_frame); let sampler_index = sampler as usize; @@ -901,11 +921,11 @@ impl Device { } } - pub fn bind_render_target(&mut self, texture_id: Option) { + pub fn bind_render_target(&mut self, texture_id: Option<(TextureId, i32)>) { debug_assert!(self.inside_frame); let fbo_id = texture_id.map_or(FBOId(self.default_fbo), |texture_id| { - self.textures.get(&texture_id).unwrap().fbo_ids[0] + self.textures.get(&texture_id.0).unwrap().fbo_ids[texture_id.1 as usize] }); if self.bound_fbo != fbo_id { @@ -928,12 +948,22 @@ impl Device { self.set_uniforms(program, projection); } - pub fn create_texture_ids(&mut self, count: i32) -> Vec { + pub fn create_texture_ids(&mut self, + count: i32, + target: TextureTarget) -> Vec { let id_list = gl::gen_textures(count); let mut texture_ids = Vec::new(); + let target = match target { + TextureTarget::Default => gl::TEXTURE_2D, + TextureTarget::Array => gl::TEXTURE_2D_ARRAY, + }; + for id in id_list { - let texture_id = TextureId(id); + let texture_id = TextureId { + name: id, + target: target, + }; let texture = Texture { id: id, @@ -980,7 +1010,7 @@ impl Device { self.raw_textures.insert(texture_id, (x0, y0, width, height)); } - fn set_texture_parameters(&mut self, filter: TextureFilter) { + fn set_texture_parameters(&mut self, target: gl::GLuint, filter: TextureFilter) { let filter = match filter { TextureFilter::Nearest => { gl::NEAREST @@ -990,21 +1020,22 @@ impl Device { } }; - gl::tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, filter as gl::GLint); - gl::tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, filter as gl::GLint); + gl::tex_parameter_i(target, gl::TEXTURE_MAG_FILTER, filter as gl::GLint); + gl::tex_parameter_i(target, gl::TEXTURE_MIN_FILTER, filter as gl::GLint); - gl::tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as gl::GLint); - gl::tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as gl::GLint); + gl::tex_parameter_i(target, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as gl::GLint); + gl::tex_parameter_i(target, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as gl::GLint); } fn upload_texture_image(&mut self, - width: u32, - height: u32, - internal_format: u32, - format: u32, - type_: u32, - pixels: Option<&[u8]>) { - gl::tex_image_2d(gl::TEXTURE_2D, + target: gl::GLuint, + width: u32, + height: u32, + internal_format: u32, + format: u32, + type_: u32, + pixels: Option<&[u8]>) { + gl::tex_image_2d(target, 0, internal_format as gl::GLint, width as gl::GLint, height as gl::GLint, @@ -1014,20 +1045,6 @@ impl Device { pixels); } - fn deinit_texture_image(&mut self, format: ImageFormat) { - let (internal_format, gl_format) = gl_texture_formats_for_image_format(format); - let type_ = gl_type_for_texture_format(format); - gl::tex_image_2d(gl::TEXTURE_2D, - 0, - internal_format, - 0, - 0, - 0, - gl_format, - type_, - None); - } - pub fn init_texture(&mut self, texture_id: TextureId, width: u32, @@ -1044,29 +1061,36 @@ impl Device { texture.width = width; texture.height = height; texture.filter = filter; - texture.mode = mode + texture.mode = mode; } let (internal_format, gl_format) = gl_texture_formats_for_image_format(format); let type_ = gl_type_for_texture_format(format); match mode { - RenderTargetMode::RenderTarget => { + RenderTargetMode::SimpleRenderTarget => { self.bind_texture(TextureSampler::Color, texture_id); - self.set_texture_parameters(filter); - self.upload_texture_image(width, + self.set_texture_parameters(texture_id.target, filter); + self.upload_texture_image(texture_id.target, + width, height, internal_format as u32, gl_format, type_, None); - self.create_fbo_for_texture_if_necessary(texture_id); + self.create_fbo_for_texture_if_necessary(texture_id, None); + } + RenderTargetMode::LayerRenderTarget(layer_count) => { + self.bind_texture(TextureSampler::Color, texture_id); + self.set_texture_parameters(texture_id.target, filter); + self.create_fbo_for_texture_if_necessary(texture_id, Some(layer_count)); } RenderTargetMode::None => { - texture_id.bind(); - self.set_texture_parameters(filter); - - self.upload_texture_image(width, height, + self.bind_texture(TextureSampler::Color, texture_id); + self.set_texture_parameters(texture_id.target, filter); + self.upload_texture_image(texture_id.target, + width, + height, internal_format as u32, gl_format, type_, @@ -1075,26 +1099,69 @@ impl Device { } } - pub fn create_fbo_for_texture_if_necessary(&mut self, texture_id: TextureId) { - if !self.textures.get(&texture_id).unwrap().fbo_ids.is_empty() { - return - } + pub fn create_fbo_for_texture_if_necessary(&mut self, + texture_id: TextureId, + layer_count: Option) { + let texture = self.textures.get_mut(&texture_id).unwrap(); + + match layer_count { + Some(layer_count) => { + debug_assert!(layer_count > 0); - let fbo_ids: Vec<_> = - gl::gen_framebuffers(1).into_iter().map(|fbo_id| FBOId(fbo_id)).collect(); - for fbo_id in &fbo_ids[..] { - gl::bind_framebuffer(gl::FRAMEBUFFER, fbo_id.0); + // If we have enough layers allocated already, just use them. + // TODO(gw): Probably worth removing some after a while if + // there is a surplus? + let current_layer_count = texture.fbo_ids.len() as i32; + if current_layer_count >= layer_count { + return; + } - gl::framebuffer_texture_2d(gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, - texture_id.0, - 0); + let (internal_format, gl_format) = gl_texture_formats_for_image_format(texture.format); + let type_ = gl_type_for_texture_format(texture.format); + + gl::tex_image_3d(texture_id.target, + 0, + internal_format as gl::GLint, + texture.width as gl::GLint, + texture.height as gl::GLint, + layer_count, + 0, + gl_format, + type_, + None); + + let needed_layer_count = layer_count - current_layer_count; + let new_fbos = gl::gen_framebuffers(needed_layer_count); + texture.fbo_ids.extend(new_fbos.into_iter().map(|id| FBOId(id))); + + for (fbo_index, fbo_id) in texture.fbo_ids.iter().enumerate() { + gl::bind_framebuffer(gl::FRAMEBUFFER, fbo_id.0); + gl::framebuffer_texture_layer(gl::FRAMEBUFFER, + gl::COLOR_ATTACHMENT0, + texture_id.name, + 0, + fbo_index as gl::GLint); + } + } + None => { + debug_assert!(texture.fbo_ids.len() == 0 || texture.fbo_ids.len() == 1); + if texture.fbo_ids.is_empty() { + let new_fbo = gl::gen_framebuffers(1)[0]; + + gl::bind_framebuffer(gl::FRAMEBUFFER, new_fbo); + + gl::framebuffer_texture_2d(gl::FRAMEBUFFER, + gl::COLOR_ATTACHMENT0, + texture_id.target, + texture_id.name, + 0); + + texture.fbo_ids.push(FBOId(new_fbo)); + } + } } gl::bind_framebuffer(gl::FRAMEBUFFER, self.default_fbo); - - self.textures.get_mut(&texture_id).unwrap().fbo_ids = fbo_ids; } pub fn resize_texture(&mut self, @@ -1108,14 +1175,14 @@ impl Device { let (old_width, old_height) = self.get_texture_dimensions(texture_id); - let temp_texture_id = self.create_texture_ids(1)[0]; + let temp_texture_id = self.create_texture_ids(1, TextureTarget::Default)[0]; self.init_texture(temp_texture_id, old_width, old_height, format, filter, mode, None); - self.create_fbo_for_texture_if_necessary(temp_texture_id); + self.create_fbo_for_texture_if_necessary(temp_texture_id, None); - self.bind_render_target(Some(texture_id)); + self.bind_render_target(Some((texture_id, 0))); self.bind_texture(TextureSampler::Color, temp_texture_id); - gl::copy_tex_sub_image_2d(gl::TEXTURE_2D, + gl::copy_tex_sub_image_2d(temp_texture_id.target, 0, 0, 0, @@ -1126,11 +1193,11 @@ impl Device { self.deinit_texture(texture_id); self.init_texture(texture_id, new_width, new_height, format, filter, mode, None); - self.create_fbo_for_texture_if_necessary(texture_id); - self.bind_render_target(Some(temp_texture_id)); + self.create_fbo_for_texture_if_necessary(texture_id, None); + self.bind_render_target(Some((temp_texture_id, 0))); self.bind_texture(TextureSampler::Color, texture_id); - gl::copy_tex_sub_image_2d(gl::TEXTURE_2D, + gl::copy_tex_sub_image_2d(texture_id.target, 0, 0, 0, @@ -1146,11 +1213,22 @@ impl Device { pub fn deinit_texture(&mut self, texture_id: TextureId) { debug_assert!(self.inside_frame); - let texture_format = self.textures[&texture_id].format; self.bind_texture(TextureSampler::Color, texture_id); - self.deinit_texture_image(texture_format); let texture = self.textures.get_mut(&texture_id).unwrap(); + let (internal_format, gl_format) = gl_texture_formats_for_image_format(texture.format); + let type_ = gl_type_for_texture_format(texture.format); + + gl::tex_image_2d(texture_id.target, + 0, + internal_format, + 0, + 0, + 0, + gl_format, + type_, + None); + if !texture.fbo_ids.is_empty() { let fbo_ids: Vec<_> = texture.fbo_ids.iter().map(|&FBOId(fbo_id)| fbo_id).collect(); gl::delete_framebuffers(&fbo_ids[..]); @@ -1402,13 +1480,14 @@ impl Device { } fn update_image_for_2d_texture(&mut self, + target: gl::GLuint, x0: gl::GLint, y0: gl::GLint, width: gl::GLint, height: gl::GLint, format: gl::GLuint, data: &[u8]) { - gl::tex_sub_image_2d(gl::TEXTURE_2D, + gl::tex_sub_image_2d(target, 0, x0, y0, width, height, @@ -1450,7 +1529,8 @@ impl Device { assert!(data.len() as u32 == bpp * width * height); self.bind_texture(TextureSampler::Color, texture_id); - self.update_image_for_2d_texture(x0 as gl::GLint, + self.update_image_for_2d_texture(texture_id.target, + x0 as gl::GLint, y0 as gl::GLint, width as gl::GLint, height as gl::GLint, @@ -1467,7 +1547,7 @@ impl Device { width: i32, height: i32) { self.bind_texture(TextureSampler::Color, texture_id); - gl::copy_tex_sub_image_2d(gl::TEXTURE_2D, + gl::copy_tex_sub_image_2d(texture_id.target, 0, dest_x, dest_y, diff --git a/webrender/src/internal_types.rs b/webrender/src/internal_types.rs index c3236dc702..a20b7aa60f 100644 --- a/webrender/src/internal_types.rs +++ b/webrender/src/internal_types.rs @@ -308,7 +308,8 @@ impl DebugColorVertex { #[derive(Copy, Clone, Debug, PartialEq)] pub enum RenderTargetMode { None, - RenderTarget, + SimpleRenderTarget, + LayerRenderTarget(i32), // Number of texture layers } #[derive(Debug)] diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index d8a607c387..148878c243 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -383,12 +383,12 @@ impl PrimitiveStore { let gpu_address = self.gpu_data32.alloc(6); self.populate_clip_data(gpu_address, clip); let mask = match masked.mask { - MaskImageSource::User(image_key) => (Some(image_key), TextureId(0)), + MaskImageSource::User(image_key) => (Some(image_key), TextureId::invalid()), MaskImageSource::Renderer(texture_id) => (None, texture_id), }; (Some(gpu_address), mask) } else { - (None, (None, TextureId(0))) + (None, (None, TextureId::invalid())) }; let metadata = match container { @@ -399,7 +399,7 @@ impl PrimitiveStore { let metadata = PrimitiveMetadata { is_opaque: is_opaque, need_to_build_cache: mask_image.is_some(), - color_texture_id: TextureId(0), + color_texture_id: TextureId::invalid(), mask_texture_id: mask_texture_id, mask_image: mask_image, clip_index: clip_index, @@ -419,7 +419,7 @@ impl PrimitiveStore { let metadata = PrimitiveMetadata { is_opaque: false, need_to_build_cache: true, - color_texture_id: TextureId(0), + color_texture_id: TextureId::invalid(), mask_texture_id: mask_texture_id, mask_image: mask_image, clip_index: clip_index, @@ -439,7 +439,7 @@ impl PrimitiveStore { let metadata = PrimitiveMetadata { is_opaque: false, need_to_build_cache: true, - color_texture_id: TextureId(0), + color_texture_id: TextureId::invalid(), mask_texture_id: mask_texture_id, mask_image: mask_image, clip_index: clip_index, @@ -459,7 +459,7 @@ impl PrimitiveStore { let metadata = PrimitiveMetadata { is_opaque: false, need_to_build_cache: mask_image.is_some(), - color_texture_id: TextureId(0), + color_texture_id: TextureId::invalid(), mask_texture_id: mask_texture_id, mask_image: mask_image, clip_index: clip_index, @@ -480,7 +480,7 @@ impl PrimitiveStore { let metadata = PrimitiveMetadata { is_opaque: false, need_to_build_cache: true, - color_texture_id: TextureId(0), + color_texture_id: TextureId::invalid(), mask_texture_id: mask_texture_id, mask_image: mask_image, clip_index: clip_index, @@ -501,7 +501,7 @@ impl PrimitiveStore { let metadata = PrimitiveMetadata { is_opaque: false, need_to_build_cache: mask_image.is_some(), - color_texture_id: TextureId(0), + color_texture_id: TextureId::invalid(), mask_texture_id: mask_texture_id, mask_image: mask_image, clip_index: clip_index, @@ -678,7 +678,7 @@ impl PrimitiveStore { Some(image_info) => image_info, }; - debug_assert!(metadata.color_texture_id == TextureId(0) || + debug_assert!(metadata.color_texture_id == TextureId::invalid() || metadata.color_texture_id == image_info.texture_id); metadata.color_texture_id = image_info.texture_id; diff --git a/webrender/src/profiler.rs b/webrender/src/profiler.rs index ff6309d0b9..4d4042ede4 100644 --- a/webrender/src/profiler.rs +++ b/webrender/src/profiler.rs @@ -231,7 +231,7 @@ impl ProfileCounter for AverageTimeProfileCounter { pub struct FrameProfileCounters { pub total_primitives: IntProfileCounter, pub visible_primitives: IntProfileCounter, - pub phases: IntProfileCounter, + pub passes: IntProfileCounter, pub targets: IntProfileCounter, } @@ -240,8 +240,8 @@ impl FrameProfileCounters { FrameProfileCounters { total_primitives: IntProfileCounter::new("Total Primitives"), visible_primitives: IntProfileCounter::new("Visible Primitives"), - phases: IntProfileCounter::new("Phases"), - targets: IntProfileCounter::new("Target switches"), + passes: IntProfileCounter::new("Passes"), + targets: IntProfileCounter::new("Render Targets"), } } } @@ -620,7 +620,7 @@ impl Profiler { self.draw_counters(&[ &frame_profile.total_primitives, &frame_profile.visible_primitives, - &frame_profile.phases, + &frame_profile.passes, &frame_profile.targets, ], debug_renderer, true); diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index 2123fe5a51..51c01a2d7c 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -288,7 +288,7 @@ impl RenderBackend { self.webgl_contexts.insert(id, ctx); self.resource_cache - .add_webgl_texture(id, TextureId(texture_id), real_size); + .add_webgl_texture(id, TextureId::new(texture_id), real_size); tx.send(Ok((id, limits))).unwrap(); }, diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 1083490417..96dee632ba 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -12,7 +12,7 @@ use batch::RasterBatch; use debug_render::DebugRenderer; use device::{Device, ProgramId, TextureId, UniformLocation, VertexFormat, GpuProfiler}; -use device::{TextureFilter, VAOId, VertexUsageHint, FileWatcherHandler}; +use device::{TextureFilter, VAOId, VertexUsageHint, FileWatcherHandler, TextureTarget}; use euclid::{Matrix4D, Point2D, Rect, Size2D}; use fnv::FnvHasher; use gleam::gl; @@ -92,7 +92,7 @@ struct VertexDataTexture { impl VertexDataTexture { fn new(device: &mut Device) -> VertexDataTexture { - let id = device.create_texture_ids(1)[0]; + let id = device.create_texture_ids(1, TextureTarget::Default)[0]; VertexDataTexture { id: id, @@ -358,7 +358,7 @@ pub struct Renderer { max_raster_op_size: u32, raster_op_target_a8: TextureId, raster_op_target_rgba8: TextureId, - render_targets: [TextureId; 2], + render_targets: Vec, gpu_profile: GpuProfiler, quad_vao_id: VAOId, @@ -497,7 +497,7 @@ impl Renderer { &mut device, options.precache_shaders); - let texture_ids = device.create_texture_ids(1024); + let texture_ids = device.create_texture_ids(1024, TextureTarget::Default); let mut texture_cache = TextureCache::new(texture_ids); let white_pixels: Vec = vec![ @@ -540,22 +540,22 @@ impl Renderer { let debug_renderer = DebugRenderer::new(&mut device); - let raster_op_target_a8 = device.create_texture_ids(1)[0]; + let raster_op_target_a8 = device.create_texture_ids(1, TextureTarget::Default)[0]; device.init_texture(raster_op_target_a8, max_raster_op_size, max_raster_op_size, ImageFormat::A8, TextureFilter::Nearest, - RenderTargetMode::RenderTarget, + RenderTargetMode::SimpleRenderTarget, None); - let raster_op_target_rgba8 = device.create_texture_ids(1)[0]; + let raster_op_target_rgba8 = device.create_texture_ids(1, TextureTarget::Default)[0]; device.init_texture(raster_op_target_rgba8, max_raster_op_size, max_raster_op_size, ImageFormat::RGBA8, TextureFilter::Nearest, - RenderTargetMode::RenderTarget, + RenderTargetMode::SimpleRenderTarget, None); let layer_texture = VertexDataTexture::new(&mut device); @@ -668,7 +668,7 @@ impl Renderer { last_time: 0, raster_op_target_a8: raster_op_target_a8, raster_op_target_rgba8: raster_op_target_rgba8, - render_targets: [TextureId(0), TextureId(0)], + render_targets: Vec::new(), max_raster_op_size: max_raster_op_size, gpu_profile: GpuProfiler::new(), quad_vao_id: quad_vao_id, @@ -1148,13 +1148,13 @@ impl Renderer { gl::disable(gl::BLEND); } - self.device.bind_render_target(Some(target_texture_id)); + self.device.bind_render_target(Some((target_texture_id, 0))); gl::viewport(0, 0, self.max_raster_op_size as gl::GLint, self.max_raster_op_size as gl::GLint); self.device.bind_program(program_id, &projection); self.device.bind_texture(TextureSampler::Color, color_texture_id); - self.device.bind_texture(TextureSampler::Mask, TextureId(0)); + self.device.bind_texture(TextureSampler::Mask, TextureId::invalid()); match blur_direction { Some(AxisDirection::Horizontal) => { @@ -1346,10 +1346,10 @@ impl Renderer { } fn draw_target(&mut self, - render_target: Option, + render_target: Option<(TextureId, i32)>, target: &RenderTarget, target_size: &Size2D, - cache_texture: TextureId, + cache_texture: Option, should_clear: bool) { self.gpu_profile.add_marker(GPU_TAG_SETUP_TARGET); @@ -1363,7 +1363,9 @@ impl Renderer { gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); gl::blend_equation(gl::FUNC_ADD); - self.device.bind_texture(TextureSampler::Cache, cache_texture); + if let Some(cache_texture) = cache_texture { + self.device.bind_texture(TextureSampler::Cache, cache_texture); + } let projection = match render_target { Some(..) => { @@ -1572,28 +1574,30 @@ impl Renderer { ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE); - if frame.phases.is_empty() { + if frame.passes.is_empty() { gl::clear_color(1.0, 1.0, 1.0, 1.0); gl::clear(gl::COLOR_BUFFER_BIT); } else { - if self.render_targets[0] == TextureId(0) { - self.render_targets[0] = self.device.create_texture_ids(1)[0]; - self.render_targets[1] = self.device.create_texture_ids(1)[0]; - self.device.init_texture(self.render_targets[0], - frame.cache_size.width as u32, - frame.cache_size.height as u32, - ImageFormat::RGBA8, - TextureFilter::Linear, - RenderTargetMode::RenderTarget, - None); + // Add new render targets to the pool if required. + let needed_targets = frame.passes.len() - 1; // framebuffer doesn't need a target! + let current_target_count = self.render_targets.len(); + if needed_targets > current_target_count { + let new_target_count = needed_targets - current_target_count; + let new_targets = self.device.create_texture_ids(new_target_count as i32, + TextureTarget::Array); + self.render_targets.extend_from_slice(&new_targets); + } - self.device.init_texture(self.render_targets[1], + // Init textures and render targets to match this scene. This shouldn't + // block in drivers, but it might be worth checking... + for (pass, texture_id) in frame.passes.iter().zip(self.render_targets.iter()) { + self.device.init_texture(*texture_id, frame.cache_size.width as u32, frame.cache_size.height as u32, ImageFormat::RGBA8, TextureFilter::Linear, - RenderTargetMode::RenderTarget, + RenderTargetMode::LayerRenderTarget(pass.targets.len() as i32), None); } @@ -1613,28 +1617,30 @@ impl Renderer { self.device.bind_texture(TextureSampler::Data64, self.data64_texture.id); self.device.bind_texture(TextureSampler::Data128, self.data128_texture.id); - for (phase_index, phase) in frame.phases.iter().enumerate() { - let mut render_target_index = 0; - - for target in &phase.targets { - if target.is_framebuffer { - let ct_index = self.render_targets[1 - render_target_index]; - self.draw_target(None, - target, - &Size2D::new(framebuffer_size.width as f32, framebuffer_size.height as f32), - ct_index, - needs_clear && phase_index == 0); - } else { - let rt_index = self.render_targets[render_target_index]; - let ct_index = self.render_targets[1 - render_target_index]; - self.draw_target(Some(rt_index), - target, - &frame.cache_size, - ct_index, - true); - render_target_index = 1 - render_target_index; - } + let mut src_id = None; + + for (pass_index, pass) in frame.passes.iter().enumerate() { + let (do_clear, size, target_id) = if pass.is_framebuffer { + (needs_clear, + Size2D::new(framebuffer_size.width as f32, framebuffer_size.height as f32), + None) + } else { + (true, frame.cache_size, Some(self.render_targets[pass_index])) + }; + + for (target_index, target) in pass.targets.iter().enumerate() { + let render_target = target_id.map(|texture_id| { + (texture_id, target_index as i32) + }); + self.draw_target(render_target, + target, + &size, + src_id, + do_clear); + } + + src_id = target_id; } } diff --git a/webrender/src/texture_cache.rs b/webrender/src/texture_cache.rs index 1a451ef3f3..c6a673a3de 100644 --- a/webrender/src/texture_cache.rs +++ b/webrender/src/texture_cache.rs @@ -691,19 +691,19 @@ impl TextureCache { let (page_list, mode) = match (format, kind) { (ImageFormat::A8, TextureCacheItemKind::Standard) => { - (&mut self.arena.pages_a8, RenderTargetMode::RenderTarget) + (&mut self.arena.pages_a8, RenderTargetMode::SimpleRenderTarget) } (ImageFormat::A8, TextureCacheItemKind::Alternate) => { - (&mut self.arena.alternate_pages_a8, RenderTargetMode::RenderTarget) + (&mut self.arena.alternate_pages_a8, RenderTargetMode::SimpleRenderTarget) } (ImageFormat::RGBA8, TextureCacheItemKind::Standard) => { - (&mut self.arena.pages_rgba8, RenderTargetMode::RenderTarget) + (&mut self.arena.pages_rgba8, RenderTargetMode::SimpleRenderTarget) } (ImageFormat::RGBA8, TextureCacheItemKind::Alternate) => { - (&mut self.arena.alternate_pages_rgba8, RenderTargetMode::RenderTarget) + (&mut self.arena.alternate_pages_rgba8, RenderTargetMode::SimpleRenderTarget) } (ImageFormat::RGB8, TextureCacheItemKind::Standard) => { - (&mut self.arena.pages_rgb8, RenderTargetMode::RenderTarget) + (&mut self.arena.pages_rgb8, RenderTargetMode::SimpleRenderTarget) } (ImageFormat::Invalid, TextureCacheItemKind::Standard) | (ImageFormat::RGBAF32, TextureCacheItemKind::Standard) | diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index 7539071ca9..de2c90082b 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -233,6 +233,9 @@ pub enum PrimitiveFlags { Scrollbar(ScrollLayerId, f32) } +#[derive(Debug, Copy, Clone)] +struct RenderTargetIndex(usize); + #[derive(Debug, Copy, Clone)] struct RenderTaskIndex(usize); @@ -427,83 +430,95 @@ struct RenderTargetContext<'a> { } pub struct RenderTarget { - pub is_framebuffer: bool, - page_allocator: TexturePage, - tasks: Vec, pub alpha_batcher: AlphaBatcher, + page_allocator: TexturePage, } impl RenderTarget { - fn new(is_framebuffer: bool) -> RenderTarget { + fn new() -> RenderTarget { RenderTarget { - is_framebuffer: is_framebuffer, - page_allocator: TexturePage::new(TextureId(0), RENDERABLE_CACHE_SIZE as u32), - tasks: Vec::new(), alpha_batcher: AlphaBatcher::new(), + page_allocator: TexturePage::new(TextureId::invalid(), RENDERABLE_CACHE_SIZE as u32), } } - fn add_render_task(&mut self, task: RenderTask) { - self.tasks.push(task); - } - fn build(&mut self, ctx: &RenderTargetContext, render_tasks: &mut RenderTaskCollection) { - // Step through each task, adding to batches as appropriate. - for task in self.tasks.drain(..) { - match task.kind { - RenderTaskKind::Alpha(info) => { - self.alpha_batcher.add_task(AlphaBatchTask { - task_id: task.id, - items: info.items, - }); - } + self.alpha_batcher.build(ctx, render_tasks); + } + + fn add_task(&mut self, task: RenderTask) { + match task.kind { + RenderTaskKind::Alpha(info) => { + self.alpha_batcher.add_task(AlphaBatchTask { + task_id: task.id, + items: info.items, + }); } } - - self.alpha_batcher.build(ctx, render_tasks); } } -pub struct RenderPhase { +pub struct RenderPass { + pub is_framebuffer: bool, + tasks: Vec, pub targets: Vec, } -impl RenderPhase { - fn new(max_target_count: usize) -> RenderPhase { - //println!("+ start render phase: targets={}", max_target_count); - let mut targets = Vec::with_capacity(max_target_count); - for index in 0..max_target_count { - targets.push(RenderTarget::new(index == max_target_count-1)); - } - - RenderPhase { - targets: targets, +impl RenderPass { + fn new(is_framebuffer: bool) -> RenderPass { + RenderPass { + is_framebuffer: is_framebuffer, + targets: vec![ RenderTarget::new() ], + tasks: Vec::new(), } } - fn add_compiled_screen_tile(&mut self, - mut tile: CompiledScreenTile, - render_tasks: &mut RenderTaskCollection) -> Option { - debug_assert!(tile.required_target_count <= self.targets.len()); - - let ok = tile.main_render_task.alloc_if_required(self.targets.len() - 1, - &mut self.targets); - - if ok { - tile.main_render_task.assign_to_targets(self.targets.len() - 1, - &mut self.targets, - render_tasks); - None - } else { - Some(tile) - } + fn add_render_task(&mut self, task: RenderTask) { + self.tasks.push(task); } fn build(&mut self, ctx: &RenderTargetContext, render_tasks: &mut RenderTaskCollection) { + // Step through each task, adding to batches as appropriate. + for mut task in self.tasks.drain(..) { + // Find a target to assign this task to, or create a new + // one if required. + match task.location { + RenderTaskLocation::Fixed(..) => {} + RenderTaskLocation::Dynamic(ref mut origin, ref size) => { + let alloc_size = Size2D::new(size.width as u32, + size.height as u32); + + let alloc_origin = self.targets + .last_mut() + .unwrap() + .page_allocator.allocate(&alloc_size); + + let alloc_origin = match alloc_origin { + Some(alloc_origin) => alloc_origin, + None => { + let mut new_target = RenderTarget::new(); + let origin = new_target.page_allocator + .allocate(&alloc_size) + .expect("Each render task must allocate <= size of one target!"); + self.targets.push(new_target); + origin + } + }; + + let alloc_origin = DevicePoint::new(alloc_origin.x as i32, + alloc_origin.y as i32); + *origin = Some((alloc_origin, RenderTargetIndex(self.targets.len() - 1))); + } + } + + render_tasks.add(&task); + self.targets.last_mut().unwrap().add_task(task); + } + for target in &mut self.targets { target.build(ctx, render_tasks); } @@ -513,7 +528,7 @@ impl RenderPhase { #[derive(Debug)] enum RenderTaskLocation { Fixed(DeviceRect), - Dynamic(Option, DeviceSize), + Dynamic(Option<(DevicePoint, RenderTargetIndex)>, DeviceSize), } #[derive(Debug)] @@ -566,7 +581,7 @@ impl RenderTask { fn write_task_data(&self) -> RenderTaskData { match self.kind { RenderTaskKind::Alpha(ref task) => { - let target_rect = self.get_target_rect(); + let (target_rect, target_index) = self.get_target_rect(); debug_assert!(target_rect.size.width == task.actual_rect.size.width); debug_assert!(target_rect.size.height == task.actual_rect.size.height); @@ -578,7 +593,7 @@ impl RenderTask { target_rect.origin.y as f32, task.actual_rect.size.width as f32, task.actual_rect.size.height as f32, - 0.0, + target_index.0 as f32, 0.0, ], } @@ -597,75 +612,36 @@ impl RenderTask { } } - fn get_target_rect(&self) -> DeviceRect { + fn get_target_rect(&self) -> (DeviceRect, RenderTargetIndex) { match self.location { - RenderTaskLocation::Fixed(rect) => rect, - RenderTaskLocation::Dynamic(origin, size) => { - DeviceRect::new(origin.expect("Should have been allocated by now!"), - size) + RenderTaskLocation::Fixed(rect) => (rect, RenderTargetIndex(0)), + RenderTaskLocation::Dynamic(origin_and_target_index, size) => { + let (origin, target_index) = origin_and_target_index.expect("Should have been allocated by now!"); + (DeviceRect::new(origin, size), target_index) } } } - fn assign_to_targets(mut self, - target_index: usize, - targets: &mut Vec, - render_tasks: &mut RenderTaskCollection) { + fn assign_to_passes(mut self, + pass_index: usize, + passes: &mut Vec) { for child in self.children.drain(..) { - child.assign_to_targets(target_index - 1, - targets, - render_tasks); + child.assign_to_passes(pass_index - 1, + passes); } - render_tasks.add(&self); - // Sanity check - can be relaxed if needed match self.location { RenderTaskLocation::Fixed(..) => { - debug_assert!(target_index == targets.len() - 1); + debug_assert!(pass_index == passes.len() - 1); } RenderTaskLocation::Dynamic(..) => { - debug_assert!(target_index < targets.len() - 1); - } - } - - let target = &mut targets[target_index]; - target.add_render_task(self); - } - - fn alloc_if_required(&mut self, - target_index: usize, - targets: &mut Vec) -> bool { - match self.location { - RenderTaskLocation::Fixed(..) => {} - RenderTaskLocation::Dynamic(ref mut origin, ref size) => { - let target = &mut targets[target_index]; - - let alloc_size = Size2D::new(size.width as u32, - size.height as u32); - - let alloc_origin = target.page_allocator.allocate(&alloc_size); - - match alloc_origin { - Some(alloc_origin) => { - *origin = Some(DevicePoint::new(alloc_origin.x as i32, - alloc_origin.y as i32)); - } - None => { - return false; - } - } + debug_assert!(pass_index < passes.len() - 1); } } - for child in &mut self.children { - if !child.alloc_if_required(target_index - 1, - targets) { - return false; - } - } - - true + let pass = &mut passes[pass_index]; + pass.add_render_task(self); } fn max_depth(&self, @@ -739,8 +715,8 @@ impl AlphaBatchKey { AlphaBatchKey { kind: AlphaBatchKind::Blend, flags: AlphaBatchKeyFlags(0), - color_texture_id: TextureId(0), - mask_texture_id: TextureId(0), + color_texture_id: TextureId::invalid(), + mask_texture_id: TextureId::invalid(), } } @@ -748,8 +724,8 @@ impl AlphaBatchKey { AlphaBatchKey { kind: AlphaBatchKind::Composite, flags: AlphaBatchKeyFlags(0), - color_texture_id: TextureId(0), - mask_texture_id: TextureId(0), + color_texture_id: TextureId::invalid(), + mask_texture_id: TextureId::invalid(), } } @@ -769,9 +745,9 @@ impl AlphaBatchKey { fn is_compatible_with(&self, other: &AlphaBatchKey) -> bool { self.kind == other.kind && self.flags == other.flags && - (self.color_texture_id == TextureId(0) || other.color_texture_id == TextureId(0) || + (self.color_texture_id == TextureId::invalid() || other.color_texture_id == TextureId::invalid() || self.color_texture_id == other.color_texture_id) && - (self.mask_texture_id == TextureId(0) || other.mask_texture_id == TextureId(0) || + (self.mask_texture_id == TextureId::invalid() || other.mask_texture_id == TextureId::invalid() || self.mask_texture_id == other.mask_texture_id) } } @@ -860,8 +836,8 @@ pub struct PrimitiveBatch { impl PrimitiveBatch { fn blend() -> PrimitiveBatch { PrimitiveBatch { - color_texture_id: TextureId(0), - mask_texture_id: TextureId(0), + color_texture_id: TextureId::invalid(), + mask_texture_id: TextureId::invalid(), transform_kind: TransformedRectKind::AxisAligned, has_complex_clip: false, blending_enabled: true, @@ -871,8 +847,8 @@ impl PrimitiveBatch { fn composite() -> PrimitiveBatch { PrimitiveBatch { - color_texture_id: TextureId(0), - mask_texture_id: TextureId(0), + color_texture_id: TextureId::invalid(), + mask_texture_id: TextureId::invalid(), transform_kind: TransformedRectKind::AxisAligned, has_complex_clip: false, blending_enabled: true, @@ -1089,7 +1065,7 @@ pub struct Frame { pub viewport_size: Size2D, pub debug_rects: Vec, pub cache_size: Size2D, - pub phases: Vec, + pub passes: Vec, pub clear_tiles: Vec, pub profile_counters: FrameProfileCounters, @@ -1114,22 +1090,27 @@ enum CompiledScreenTileInfo { #[derive(Debug)] struct CompiledScreenTile { main_render_task: RenderTask, - required_target_count: usize, + required_pass_count: usize, info: CompiledScreenTileInfo, } impl CompiledScreenTile { fn new(main_render_task: RenderTask, info: CompiledScreenTileInfo) -> CompiledScreenTile { - let mut required_target_count = 0; - main_render_task.max_depth(0, &mut required_target_count); + let mut required_pass_count = 0; + main_render_task.max_depth(0, &mut required_pass_count); CompiledScreenTile { main_render_task: main_render_task, - required_target_count: required_target_count, + required_pass_count: required_pass_count, info: info, } } + + fn build(self, passes: &mut Vec) { + self.main_render_task.assign_to_passes(passes.len() - 1, + passes); + } } #[derive(Debug, Eq, PartialEq, Copy, Clone)] @@ -2045,10 +2026,13 @@ impl FrameBuilder { // Build list of passes, target allocs that each tile needs. let mut compiled_screen_tiles = Vec::new(); + let mut max_passes_needed = 0; for screen_tile in screen_tiles { let rect = screen_tile.rect; // TODO(gw): Remove clone here match screen_tile.compile(&ctx) { Some(compiled_screen_tile) => { + max_passes_needed = cmp::max(max_passes_needed, + compiled_screen_tile.required_pass_count); if self.debug { let (label, color) = match &compiled_screen_tile.info { &CompiledScreenTileInfo::SimpleAlpha(prim_count) => { @@ -2074,44 +2058,26 @@ impl FrameBuilder { } } - let mut phases = Vec::new(); + let mut passes = Vec::new(); let static_render_task_count = ctx.render_task_id_counter.load(Ordering::SeqCst); let mut render_tasks = RenderTaskCollection::new(static_render_task_count); if !compiled_screen_tiles.is_empty() { - // Sort by pass count to minimize render target switches. - compiled_screen_tiles.sort_by(|a, b| { - let a_passes = a.required_target_count; - let b_passes = b.required_target_count; - b_passes.cmp(&a_passes) - }); - - // Do the allocations now, assigning each tile to a render - // phase as required. - - let mut current_phase = RenderPhase::new(compiled_screen_tiles[0].required_target_count); + // Do the allocations now, assigning each tile's tasks to a render + // pass and target as required. + for index in 0..max_passes_needed { + passes.push(RenderPass::new(index == max_passes_needed-1)); + } for compiled_screen_tile in compiled_screen_tiles { - if let Some(failed_tile) = current_phase.add_compiled_screen_tile(compiled_screen_tile, - &mut render_tasks) { - let full_phase = mem::replace(&mut current_phase, - RenderPhase::new(failed_tile.required_target_count)); - phases.push(full_phase); - - let result = current_phase.add_compiled_screen_tile(failed_tile, - &mut render_tasks); - assert!(result.is_none(), "TODO: Handle single tile not fitting in render phase."); - } + compiled_screen_tile.build(&mut passes); } - phases.push(current_phase); - - //println!("rendering: phase count={}", phases.len()); - for phase in &mut phases { - phase.build(&ctx, &mut render_tasks); + for pass in passes.iter_mut().rev() { + pass.build(&ctx, &mut render_tasks); - profile_counters.phases.inc(); - profile_counters.targets.add(phase.targets.len()); + profile_counters.passes.inc(); + profile_counters.targets.add(pass.targets.len()); } } @@ -2119,7 +2085,7 @@ impl FrameBuilder { viewport_size: self.screen_rect.size, debug_rects: debug_rects, profile_counters: profile_counters, - phases: phases, + passes: passes, clear_tiles: clear_tiles, cache_size: Size2D::new(RENDERABLE_CACHE_SIZE as f32, RENDERABLE_CACHE_SIZE as f32),