diff --git a/res/blend.vs.glsl b/res/blend.vs.glsl index 405c7184bb..6e9ac43c68 100644 --- a/res/blend.vs.glsl +++ b/res/blend.vs.glsl @@ -1,6 +1,6 @@ void main(void) { - vColorTexCoord = aColorTexCoord; - vMaskTexCoord = aMaskTexCoord / 65535.0; + vColorTexCoord = aColorTexCoordRectTop.xy; + vMaskTexCoord = aMaskTexCoordRectTop.xy / 65535.0; gl_Position = uTransform * vec4(aPosition, 1.0); } diff --git a/res/blit.vs.glsl b/res/blit.vs.glsl index d64135b04c..6cd9201b3c 100644 --- a/res/blit.vs.glsl +++ b/res/blit.vs.glsl @@ -1,7 +1,7 @@ void main(void) { - vColor = aColor / 255.0; - vColorTexCoord = aColorTexCoord; + vColor = aColorRectTL / 255.0; + vColorTexCoord = aColorTexCoordRectTop.xy; vec4 pos = vec4(aPosition, 1.0); pos.xy = floor(pos.xy * uDevicePixelRatio + 0.5) / uDevicePixelRatio; gl_Position = uTransform * pos; diff --git a/res/blur.vs.glsl b/res/blur.vs.glsl index 4307ee9987..841275d7cc 100644 --- a/res/blur.vs.glsl +++ b/res/blur.vs.glsl @@ -1,6 +1,6 @@ void main(void) { - vColorTexCoord = aColorTexCoord; + vColorTexCoord = aColorTexCoordRectTop.xy; vBorderPosition = aBorderPosition; vBlurRadius = aBlurRadius; vDestTextureSize = aDestTextureSize; diff --git a/res/border.vs.glsl b/res/border.vs.glsl index d214d41fe0..a002b423d6 100644 --- a/res/border.vs.glsl +++ b/res/border.vs.glsl @@ -1,6 +1,6 @@ void main(void) { - vColor = aColor; + vColor = aColorRectTL; vPosition = aPosition.xy; vBorderPosition = aBorderPosition; vBorderRadii = aBorderRadii; diff --git a/res/box_shadow.vs.glsl b/res/box_shadow.vs.glsl index 61f26664df..2d623ce7bc 100644 --- a/res/box_shadow.vs.glsl +++ b/res/box_shadow.vs.glsl @@ -1,7 +1,7 @@ void main(void) { vPosition = aPosition.xy; - vColor = aColor; + vColor = aColorRectTL; vBorderPosition = aBorderPosition; vBorderRadii = aBorderRadii; vBlurRadius = aBlurRadius; diff --git a/res/clear.vs.glsl b/res/clear.vs.glsl index 2220f968cc..b426b8814c 100644 --- a/res/clear.vs.glsl +++ b/res/clear.vs.glsl @@ -1,5 +1,5 @@ void main(void) { - vColor = aColor / 255.0; + vColor = aColorRectTL / 255.0; gl_Position = uTransform * vec4(aPosition, 1.0); } diff --git a/res/debug_color.vs.glsl b/res/debug_color.vs.glsl index 7871506e01..ba71c96474 100644 --- a/res/debug_color.vs.glsl +++ b/res/debug_color.vs.glsl @@ -1,6 +1,6 @@ void main(void) { - vColor = aColor; + vColor = aColorRectTL; vec4 pos = vec4(aPosition, 1.0); pos.xy = floor(pos.xy * uDevicePixelRatio + 0.5) / uDevicePixelRatio; gl_Position = uTransform * pos; diff --git a/res/debug_font.vs.glsl b/res/debug_font.vs.glsl index d44f81ab09..0ed5e46464 100644 --- a/res/debug_font.vs.glsl +++ b/res/debug_font.vs.glsl @@ -1,7 +1,7 @@ void main(void) { - vColor = aColor; - vColorTexCoord = aColorTexCoord; + vColor = aColorRectTL; + vColorTexCoord = aColorTexCoordRectTop.xy; vec4 pos = vec4(aPosition, 1.0); pos.xy = floor(pos.xy * uDevicePixelRatio + 0.5) / uDevicePixelRatio; gl_Position = uTransform * pos; diff --git a/res/es2_common.vs.glsl b/res/es2_common.vs.glsl index 8f98b5076a..d04bd8e023 100644 --- a/res/es2_common.vs.glsl +++ b/res/es2_common.vs.glsl @@ -13,15 +13,26 @@ uniform float uDevicePixelRatio; uniform vec4 uTileParams[64]; attribute vec3 aPosition; -attribute vec4 aColor; -attribute vec2 aColorTexCoord; -attribute vec2 aMaskTexCoord; +attribute vec4 aPositionRect; // Width can be negative to flip horizontally (for border corners). +attribute vec4 aColorRectTL; +attribute vec4 aColorRectTR; +attribute vec4 aColorRectBR; +attribute vec4 aColorRectBL; +attribute vec4 aColorTexCoordRectTop; +attribute vec4 aColorTexCoordRectBottom; +attribute vec4 aMaskTexCoordRectTop; +attribute vec4 aMaskTexCoordRectBottom; attribute vec4 aBorderPosition; attribute vec4 aBorderRadii; attribute vec2 aSourceTextureSize; attribute vec2 aDestTextureSize; attribute float aBlurRadius; -attribute vec4 aMisc; // x = matrix index; w = tile params index +// x = matrix index; y = clip-in rect; z = clip-out rect; w = tile params index. +// +// A negative w value activates border corner mode. In this mode, the TR and BL colors are ignored, +// the color of the top left corner applies to all vertices of the top left triangle, and the color +// of the bottom right corner applies to all vertices of the bottom right triangle. +attribute vec4 aMisc; varying vec2 vPosition; varying vec4 vColor; @@ -35,3 +46,13 @@ varying float vBlurRadius; varying vec4 vTileParams; varying vec4 vClipInRect; varying vec4 vClipOutRect; + +int Bottom7Bits(int value) { + return value % 0x80; +} + +bool IsBottomTriangle() { + // FIXME(pcwalton): No gl_VertexID in OpenGL ES 2. We'll need some extra data. + return false; +} + diff --git a/res/filter.vs.glsl b/res/filter.vs.glsl index ea1d9e621f..7908086b45 100644 --- a/res/filter.vs.glsl +++ b/res/filter.vs.glsl @@ -1,7 +1,7 @@ void main(void) { - vColorTexCoord = aColorTexCoord; - vMaskTexCoord = aMaskTexCoord; + vColorTexCoord = aColorTexCoordRectTop.xy; + vMaskTexCoord = aMaskTexCoordRectTop.xy; gl_Position = uTransform * vec4(aPosition, 1.0); } diff --git a/res/gl3_common.vs.glsl b/res/gl3_common.vs.glsl index 62271e6101..a4dc0d60d9 100644 --- a/res/gl3_common.vs.glsl +++ b/res/gl3_common.vs.glsl @@ -13,15 +13,26 @@ uniform float uDevicePixelRatio; uniform vec4 uTileParams[64]; in vec3 aPosition; -in vec4 aColor; -in vec2 aColorTexCoord; -in vec2 aMaskTexCoord; +in vec4 aPositionRect; // Width can be negative to flip horizontally (for border corners). +in vec4 aColorRectTL; +in vec4 aColorRectTR; +in vec4 aColorRectBR; +in vec4 aColorRectBL; +in vec4 aColorTexCoordRectTop; +in vec4 aColorTexCoordRectBottom; +in vec4 aMaskTexCoordRectTop; +in vec4 aMaskTexCoordRectBottom; in vec4 aBorderPosition; in vec4 aBorderRadii; in vec2 aSourceTextureSize; in vec2 aDestTextureSize; in float aBlurRadius; -in vec4 aMisc; // x = matrix index; w = tile params index +// x = matrix index; y = clip-in rect; z = clip-out rect; w = tile params index. +// +// A negative w value activates border corner mode. In this mode, the TR and BL colors are ignored, +// the color of the top left corner applies to all vertices of the top left triangle, and the color +// of the bottom right corner applies to all vertices of the bottom right triangle. +in vec4 aMisc; out vec2 vPosition; out vec4 vColor; @@ -35,3 +46,12 @@ out float vBlurRadius; out vec4 vTileParams; out vec4 vClipInRect; out vec4 vClipOutRect; + +int Bottom7Bits(int value) { + return value & 0x7f; +} + +bool IsBottomTriangle() { + return gl_VertexID > 2; +} + diff --git a/res/quad.vs.glsl b/res/quad.vs.glsl index 7592c44abf..d63a9a8571 100644 --- a/res/quad.vs.glsl +++ b/res/quad.vs.glsl @@ -12,28 +12,60 @@ vec2 SnapToPixels(vec2 pos) void main(void) { - // Normalize the vertex color - vColor = aColor / 255.0; - // Extract the image tiling parameters. // These are passed to the fragment shader, since // the uv interpolation must be done per-fragment. - vTileParams = uTileParams[int(aMisc.w)]; + vTileParams = uTileParams[Bottom7Bits(int(aMisc.w))]; - // Normalize the mask texture coordinates. - vec2 maskTexCoord = aMaskTexCoord / 65535.0; - vec2 colorTexCoord = aColorTexCoord; + // Determine the position, color, and mask texture coordinates of this vertex. + vec4 localPos = vec4(0.0, 0.0, 0.0, 1.0); + bool isBorderCorner = int(aMisc.w) >= 0x80; + bool isBottomTriangle = IsBottomTriangle(); + if (aPosition.y == 0.0) { + localPos.y = aPositionRect.y; + if (aPosition.x == 0.0) { + localPos.x = aPositionRect.x; + vColorTexCoord = aColorTexCoordRectTop.xy; + vMaskTexCoord = aMaskTexCoordRectTop.xy; + if (!isBorderCorner) { + vColor = aColorRectTL; + } else { + vColor = !isBottomTriangle ? aColorRectTR : aColorRectBL; + } + } else { + localPos.x = aPositionRect.x + aPositionRect.z; + vColorTexCoord = aColorTexCoordRectTop.zw; + vMaskTexCoord = aMaskTexCoordRectTop.zw; + vColor = aColorRectTR; + } + } else { + localPos.y = aPositionRect.y + aPositionRect.w; + if (aPosition.x == 0.0) { + localPos.x = aPositionRect.x; + vColorTexCoord = aColorTexCoordRectBottom.zw; + vMaskTexCoord = aMaskTexCoordRectBottom.zw; + vColor = aColorRectBL; + } else { + localPos.x = aPositionRect.x + aPositionRect.z; + vColorTexCoord = aColorTexCoordRectBottom.xy; + vMaskTexCoord = aMaskTexCoordRectBottom.xy; + if (!isBorderCorner) { + vColor = aColorRectBR; + } else { + vColor = !isBottomTriangle ? aColorRectTR : aColorRectBL; + } + } + } - // Pass through the color and mask texture coordinates to fragment shader - vColorTexCoord = colorTexCoord; - vMaskTexCoord = maskTexCoord; + // Normalize the vertex color and mask texture coordinates. + vColor /= 255.0; + vMaskTexCoord /= 65535.0; // Extract the complete (stacking context + css transform) transform // for this vertex. Transform the position by it. - vec4 offsetParams = uOffsets[int(aMisc.x)]; - mat4 matrix = uMatrixPalette[int(aMisc.x)]; + vec4 offsetParams = uOffsets[Bottom7Bits(int(aMisc.x))]; + mat4 matrix = uMatrixPalette[Bottom7Bits(int(aMisc.x))]; - vec4 localPos = vec4(aPosition.xy, 0.0, 1.0); localPos.xy += offsetParams.xy; vClipInRect = uClipRects[int(aMisc.y)]; diff --git a/src/batch.rs b/src/batch.rs index a22a2d8e00..bbb00115ea 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -1,10 +1,12 @@ use device::{ProgramId, TextureId}; use euclid::{Point2D, Rect, Size2D}; -use internal_types::{MAX_RECT, AxisDirection, PackedVertex, PackedVertexForTextureCacheUpdate, Primitive}; +use internal_types::{MAX_RECT, AxisDirection, PackedVertexColorMode, PackedVertexForQuad}; +use internal_types::{PackedVertexForTextureCacheUpdate, RectUv}; use std::sync::atomic::Ordering::SeqCst; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; +use std::sync::Arc; use std::u16; -use webrender_traits::{ComplexClipRegion}; +use webrender_traits::{ColorF, ComplexClipRegion}; pub const MAX_MATRICES_PER_BATCH: usize = 32; pub const MAX_CLIP_RECTS_PER_BATCH: usize = 64; @@ -60,16 +62,16 @@ impl VertexBufferId { pub struct VertexBuffer { pub id: VertexBufferId, - pub vertices: Vec, - pub indices: Vec, + pub instance_count: u32, + pub vertices: Vec, } impl VertexBuffer { pub fn new() -> VertexBuffer { VertexBuffer { id: VertexBufferId::new(), - vertices: Vec::new(), - indices: Vec::new(), + instance_count: 0, + vertices: vec![], } } } @@ -78,14 +80,14 @@ impl VertexBuffer { pub struct Batch { pub color_texture_id: TextureId, pub mask_texture_id: TextureId, - pub first_vertex: u32, - pub index_count: u16, + pub first_instance: u32, + pub instance_count: u32, pub tile_params: Vec, pub clip_rects: Vec>, } impl Batch { - pub fn new(color_texture_id: TextureId, mask_texture_id: TextureId, first_vertex: u32) + pub fn new(color_texture_id: TextureId, mask_texture_id: TextureId, first_instance: u32) -> Batch { let default_tile_params = vec![ TileParams { @@ -103,8 +105,8 @@ impl Batch { Batch { color_texture_id: color_texture_id, mask_texture_id: mask_texture_id, - first_vertex: first_vertex, - index_count: 0, + first_instance: first_instance, + instance_count: 0, tile_params: default_tile_params, clip_rects: default_clip_rects, } @@ -123,13 +125,11 @@ impl Batch { pub fn can_add_to_batch(&self, color_texture_id: TextureId, mask_texture_id: TextureId, - index_count: u16, needs_tile_params: bool, clip_in_rect: &Rect, clip_out_rect: &Option>) -> bool { let color_texture_ok = color_texture_id == self.color_texture_id; let mask_texture_ok = mask_texture_id == self.mask_texture_id; - let index_count_ok = (self.index_count as u32 + index_count as u32) < u16::MAX as u32; let tile_params_ok = !needs_tile_params || self.tile_params.len() < MAX_TILE_PARAMS_PER_BATCH; @@ -155,17 +155,15 @@ impl Batch { color_texture_ok && mask_texture_ok && - index_count_ok && tile_params_ok && clip_rects_ok } pub fn add_draw_item(&mut self, - index_count: u16, tile_params: Option, clip_in_rect: &Rect, clip_out_rect: &Option>) -> (u8, u8, u8) { - self.index_count += index_count; + self.instance_count += 1; let tile_params_index = tile_params.map_or(INVALID_TILE_PARAM, |tile_params| { let index = self.tile_params.len(); @@ -298,86 +296,68 @@ impl<'a> BatchBuilder<'a> { self.complex_clip = None; } - pub fn add_draw_item(&mut self, + // Colors are in the order: top left, top right, bottom right, bottom left. + pub fn add_rectangle(&mut self, color_texture_id: TextureId, mask_texture_id: TextureId, - primitive: Primitive, - vertices: &mut [PackedVertex], - tile_params: Option,) { - if let Some(ref clip_in_rect) = self.cached_clip_in_rect { - let index_count = match primitive { - Primitive::Rectangles => { - (vertices.len() / 4 * 6) as u16 - } - Primitive::Triangles => vertices.len() as u16, - }; - - let need_new_batch = match self.batches.last_mut() { - Some(batch) => { - !batch.can_add_to_batch(color_texture_id, - mask_texture_id, - index_count, - tile_params.is_some(), - clip_in_rect, - &self.clip_out_rect) - } - None => { - true - } - }; - - let index_offset = self.vertex_buffer.vertices.len(); - - if need_new_batch { - self.batches.push(Batch::new(color_texture_id, - mask_texture_id, - self.vertex_buffer.indices.len() as u32)); - } - - match primitive { - Primitive::Rectangles => { - for i in (0..vertices.len()).step_by(4) { - let index_base = (index_offset + i) as u16; - debug_assert!(index_base as usize == index_offset + i); - self.vertex_buffer.indices.push(index_base + 0); - self.vertex_buffer.indices.push(index_base + 1); - self.vertex_buffer.indices.push(index_base + 2); - self.vertex_buffer.indices.push(index_base + 2); - self.vertex_buffer.indices.push(index_base + 3); - self.vertex_buffer.indices.push(index_base + 1); + pos_rect: &Rect, + uv_rect: &RectUv, + muv_rect: &RectUv, + colors: &[ColorF; 4], + color_mode: PackedVertexColorMode, + tile_params: Option) { + let (tile_params_index, + clip_in_rect_index, + clip_out_rect_index) = match self.cached_clip_in_rect { + None => return, + Some(ref clip_in_rect) => { + let need_new_batch = match self.batches.last_mut() { + Some(batch) => { + !batch.can_add_to_batch(color_texture_id, + mask_texture_id, + tile_params.is_some(), + clip_in_rect, + &self.clip_out_rect) } - } - Primitive::Triangles => { - for i in (0..vertices.len()).step_by(3) { - let index_base = (index_offset + i) as u16; - debug_assert!(index_base as usize == index_offset + i); - self.vertex_buffer.indices.push(index_base + 0); - self.vertex_buffer.indices.push(index_base + 1); - self.vertex_buffer.indices.push(index_base + 2); + None => { + true } + }; + + if need_new_batch { + self.batches.push(Batch::new(color_texture_id, + mask_texture_id, + self.vertex_buffer.instance_count)); } - } - let (tile_params_index, - clip_in_rect_index, - clip_out_rect_index) = self.batches.last_mut().unwrap().add_draw_item(index_count, - tile_params, - clip_in_rect, - &self.clip_out_rect); - - for vertex in vertices.iter_mut() { - vertex.matrix_index = self.current_matrix_index; - vertex.tile_params_index = tile_params_index; - vertex.clip_in_rect_index = clip_in_rect_index; - vertex.clip_out_rect_index = clip_out_rect_index; + self.batches.last_mut().unwrap().add_draw_item(tile_params, + clip_in_rect, + &self.clip_out_rect) } + }; - self.vertex_buffer.vertices.extend_from_slice(vertices); + let mut vertex = PackedVertexForQuad::new(pos_rect, colors, uv_rect, muv_rect, color_mode); + vertex.matrix_index = self.current_matrix_index; + vertex.tile_params_index = vertex.tile_params_index | tile_params_index; + vertex.clip_in_rect_index = clip_in_rect_index; + vertex.clip_out_rect_index = clip_out_rect_index; - // TODO(gw): Handle exceeding u16 index buffer! - debug_assert!(self.vertex_buffer.vertices.len() < 65535); + self.push_vertex_for_rectangle(vertex); + + self.vertex_buffer.instance_count += 1 + } + + #[cfg(any(target_os = "android", target_os = "gonk"))] + fn push_vertex_for_rectangle(&mut self, vertex: PackedVertexForQuad) { + for _ in 0..6 { + self.vertex_buffer.vertices.push(vertex); } } + + #[cfg(not(any(target_os = "android", target_os = "gonk")))] + fn push_vertex_for_rectangle(&mut self, vertex: PackedVertexForQuad) { + self.vertex_buffer.vertices.push(vertex); + } } /// A batch for raster jobs. diff --git a/src/batch_builder.rs b/src/batch_builder.rs index ddd7e94fbe..01c8c35e05 100644 --- a/src/batch_builder.rs +++ b/src/batch_builder.rs @@ -3,11 +3,9 @@ use batch::{BatchBuilder, TileParams}; use device::TextureId; use euclid::{Rect, Point2D, Size2D}; use fnv::FnvHasher; -use internal_types::{RectColors, RectPolygon}; -use internal_types::{RectUv, BorderRadiusRasterOp, RasterItem}; -use internal_types::{GlyphKey, PackedVertex}; -use internal_types::{AxisDirection, Primitive}; -use internal_types::{BasicRotationAngle, BoxShadowRasterOp, RectSide}; +use internal_types::{AxisDirection, BasicRotationAngle, BorderRadiusRasterOp, BoxShadowRasterOp}; +use internal_types::{GlyphKey, PackedVertexColorMode, RasterItem, RectColors, RectPolygon}; +use internal_types::{RectSide, RectUv}; use renderer::BLUR_INFLATION_FACTOR; use resource_cache::ResourceCache; use std::collections::HashMap; @@ -46,32 +44,13 @@ impl<'a> BatchBuilder<'a> { return } - let mut vertices = [ - PackedVertex::from_points(&pos_rect.origin, - &colors[0], - &uv_rect.top_left, - &muv_rect.top_left), - - PackedVertex::from_points(&pos_rect.top_right(), - &colors[1], - &uv_rect.top_right, - &muv_rect.top_right), - - PackedVertex::from_points(&pos_rect.bottom_left(), - &colors[3], - &uv_rect.bottom_left, - &muv_rect.bottom_left), - - PackedVertex::from_points(&pos_rect.bottom_right(), - &colors[2], - &uv_rect.bottom_right, - &muv_rect.bottom_right), - ]; - - self.add_draw_item(color_texture_id, + self.add_rectangle(color_texture_id, mask_texture_id, - Primitive::Rectangles, - &mut vertices, + pos_rect, + uv_rect, + muv_rect, + colors, + PackedVertexColorMode::Gradient, tile_params); } @@ -384,47 +363,18 @@ impl<'a> BatchBuilder<'a> { } } - let mut vertex_buffer = Vec::new(); for (texture_id, rect_buffer) in text_batches { - vertex_buffer.clear(); - for rect in rect_buffer { - let x0 = rect.pos.origin.x; - let y0 = rect.pos.origin.y; - let x1 = x0 + rect.pos.size.width; - let y1 = y0 + rect.pos.size.height; - - vertex_buffer.push(PackedVertex::from_components( - x0, y0, - color, - rect.varyings.top_left.x, rect.varyings.top_left.y, - dummy_mask_image.uv_rect.top_left.x, - dummy_mask_image.uv_rect.top_left.y)); - vertex_buffer.push(PackedVertex::from_components( - x1, y0, - color, - rect.varyings.top_right.x, rect.varyings.top_right.y, - dummy_mask_image.uv_rect.top_right.x, - dummy_mask_image.uv_rect.top_right.y)); - vertex_buffer.push(PackedVertex::from_components( - x0, y1, - color, - rect.varyings.bottom_left.x, rect.varyings.bottom_left.y, - dummy_mask_image.uv_rect.bottom_left.x, - dummy_mask_image.uv_rect.bottom_left.y)); - vertex_buffer.push(PackedVertex::from_components( - x1, y1, - color, - rect.varyings.bottom_right.x, rect.varyings.bottom_right.y, - dummy_mask_image.uv_rect.bottom_right.x, - dummy_mask_image.uv_rect.bottom_right.y)); + self.add_rectangle(texture_id, + dummy_mask_image.texture_id, + &rect.pos, + &rect.varyings, + &dummy_mask_image.uv_rect, + &[*color, *color, *color, *color], + PackedVertexColorMode::Gradient, + None); } - self.add_draw_item(texture_id, - dummy_mask_image.texture_id, - Primitive::Rectangles, - &mut vertex_buffer, - None); } } @@ -551,32 +501,14 @@ impl<'a> BatchBuilder<'a> { // To fix this, use a bit of trigonometry to supply the rectangles as // axis-aligned, and then the complex clipping will just work! - let mut vertices = [ - PackedVertex::from_points(&Point2D::new(x0, y0), - &color0, - &white_image.uv_rect.top_left, - &dummy_mask_image.uv_rect.top_left), - - PackedVertex::from_points(&Point2D::new(x1, y1), - &color1, - &white_image.uv_rect.top_left, - &dummy_mask_image.uv_rect.top_left), - - PackedVertex::from_points(&Point2D::new(x3, y3), - &color0, - &white_image.uv_rect.top_left, - &dummy_mask_image.uv_rect.top_left), - - PackedVertex::from_points(&Point2D::new(x2, y2), - &color1, - &white_image.uv_rect.top_left, - &dummy_mask_image.uv_rect.top_left), - ]; - - self.add_draw_item(white_image.texture_id, + let rect = Rect::new(Point2D::new(x0, y0), Size2D::new(x3 - x0, y3 - y0)); + self.add_rectangle(white_image.texture_id, dummy_mask_image.texture_id, - Primitive::Rectangles, - &mut vertices, + &rect, + &white_image.uv_rect, + &dummy_mask_image.uv_rect, + &[*color0, *color1, *color0, *color1], + PackedVertexColorMode::Gradient, None); } } @@ -1409,59 +1341,58 @@ impl<'a> BatchBuilder<'a> { let v0; let v1; - let muv0; - let muv1; - let muv2; - let muv3; + let muv; match rotation_angle { BasicRotationAngle::Upright => { v0 = rect_pos_uv.pos.origin; v1 = rect_pos_uv.pos.bottom_right(); - muv0 = rect_pos_uv.varyings.top_left; - muv1 = rect_pos_uv.varyings.top_right; - muv2 = rect_pos_uv.varyings.bottom_right; - muv3 = rect_pos_uv.varyings.bottom_left; + muv = RectUv { + top_left: rect_pos_uv.varyings.top_left, + top_right: rect_pos_uv.varyings.top_right, + bottom_right: rect_pos_uv.varyings.bottom_right, + bottom_left: rect_pos_uv.varyings.bottom_left, + } } BasicRotationAngle::Clockwise90 => { v0 = rect_pos_uv.pos.top_right(); v1 = rect_pos_uv.pos.bottom_left(); - muv0 = rect_pos_uv.varyings.top_right; - muv1 = rect_pos_uv.varyings.top_left; - muv2 = rect_pos_uv.varyings.bottom_left; - muv3 = rect_pos_uv.varyings.bottom_right; + muv = RectUv { + top_left: rect_pos_uv.varyings.top_right, + top_right: rect_pos_uv.varyings.top_left, + bottom_right: rect_pos_uv.varyings.bottom_left, + bottom_left: rect_pos_uv.varyings.bottom_right, + } } BasicRotationAngle::Clockwise180 => { v0 = rect_pos_uv.pos.bottom_right(); v1 = rect_pos_uv.pos.origin; - muv0 = rect_pos_uv.varyings.bottom_right; - muv1 = rect_pos_uv.varyings.bottom_left; - muv2 = rect_pos_uv.varyings.top_left; - muv3 = rect_pos_uv.varyings.top_right; + muv = RectUv { + top_left: rect_pos_uv.varyings.bottom_right, + top_right: rect_pos_uv.varyings.bottom_left, + bottom_right: rect_pos_uv.varyings.top_left, + bottom_left: rect_pos_uv.varyings.top_right, + } } BasicRotationAngle::Clockwise270 => { v0 = rect_pos_uv.pos.bottom_left(); v1 = rect_pos_uv.pos.top_right(); - muv0 = rect_pos_uv.varyings.bottom_left; - muv1 = rect_pos_uv.varyings.bottom_right; - muv2 = rect_pos_uv.varyings.top_right; - muv3 = rect_pos_uv.varyings.top_left; + muv = RectUv { + top_left: rect_pos_uv.varyings.bottom_left, + top_right: rect_pos_uv.varyings.bottom_right, + bottom_right: rect_pos_uv.varyings.top_right, + bottom_left: rect_pos_uv.varyings.top_left, + } } } - let mut vertices = [ - PackedVertex::from_components(v0.x, v0.y, color0, 0.0, 0.0, muv0.x, muv0.y), - PackedVertex::from_components(v1.x, v1.y, color0, 0.0, 0.0, muv2.x, muv2.y), - PackedVertex::from_components(v0.x, v1.y, color0, 0.0, 0.0, muv3.x, muv3.y), - PackedVertex::from_components(v0.x, v0.y, color1, 0.0, 0.0, muv0.x, muv0.y), - PackedVertex::from_components(v1.x, v0.y, color1, 0.0, 0.0, muv1.x, muv1.y), - PackedVertex::from_components(v1.x, v1.y, color1, 0.0, 0.0, muv2.x, muv2.y), - ]; - - self.add_draw_item(white_image.texture_id, + self.add_rectangle(white_image.texture_id, mask_image.texture_id, - Primitive::Triangles, - &mut vertices, - None); + &Rect::new(v0, Size2D::new(v1.x - v0.x, v1.y - v0.y)), + &RectUv::zero(), + &muv, + &[*color1, *color1, *color0, *color0], + PackedVertexColorMode::BorderCorner, + None) } fn add_color_image_rectangle(&mut self, diff --git a/src/debug_render.rs b/src/debug_render.rs index 6b24b6a47a..dbd3d77699 100644 --- a/src/debug_render.rs +++ b/src/debug_render.rs @@ -28,9 +28,9 @@ impl DebugRenderer { let font_program_id = device.create_program("debug_font"); let color_program_id = device.create_program("debug_color"); - let font_vao = device.create_vao(VertexFormat::DebugFont); - let line_vao = device.create_vao(VertexFormat::DebugColor); - let tri_vao = device.create_vao(VertexFormat::DebugColor); + let font_vao = device.create_vao(VertexFormat::DebugFont, None); + 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]; device.init_texture(font_texture_id, @@ -179,16 +179,16 @@ impl DebugRenderer { device.update_vao_indices(self.tri_vao, &self.tri_indices, VertexUsageHint::Dynamic); - device.update_vao_vertices(self.tri_vao, - &self.tri_vertices, - VertexUsageHint::Dynamic); + device.update_vao_main_vertices(self.tri_vao, + &self.tri_vertices, + VertexUsageHint::Dynamic); device.draw_triangles_u32(0, self.tri_indices.len() as gl::GLint); // Lines device.bind_vao(self.line_vao); - device.update_vao_vertices(self.line_vao, - &self.line_vertices, - VertexUsageHint::Dynamic); + device.update_vao_main_vertices(self.line_vao, + &self.line_vertices, + VertexUsageHint::Dynamic); device.draw_nonindexed_lines(0, self.line_vertices.len() as gl::GLint); // Glyphs @@ -198,9 +198,9 @@ impl DebugRenderer { device.update_vao_indices(self.font_vao, &self.font_indices, VertexUsageHint::Dynamic); - device.update_vao_vertices(self.font_vao, - &self.font_vertices, - VertexUsageHint::Dynamic); + device.update_vao_main_vertices(self.font_vao, + &self.font_vertices, + VertexUsageHint::Dynamic); device.draw_triangles_u32(0, self.font_indices.len() as gl::GLint); } diff --git a/src/device.rs b/src/device.rs index 03b2c018c9..26e376cb4e 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,9 +1,9 @@ use euclid::Matrix4; use fnv::FnvHasher; use gleam::gl; -use internal_types::{PackedVertex, PackedVertexForTextureCacheUpdate, RenderTargetMode}; -use internal_types::{TextureSampler, VertexAttribute}; -use internal_types::{DebugFontVertex, DebugColorVertex}; +use internal_types::{PackedColor, PackedVertex, PackedVertexForQuad}; +use internal_types::{PackedVertexForTextureCacheUpdate, RenderTargetMode, TextureSampler}; +use internal_types::{VertexAttribute, DebugFontVertex, DebugColorVertex}; use notify::{self, Watcher}; use std::collections::HashMap; use std::collections::hash_state::DefaultState; @@ -39,6 +39,69 @@ static VERTEX_SHADER_PREAMBLE: &'static str = "es2_common.vs.glsl"; #[cfg(not(any(target_os = "android", target_os = "gonk")))] static VERTEX_SHADER_PREAMBLE: &'static str = "gl3_common.vs.glsl"; +static QUAD_VERTICES: [PackedVertex; 6] = [ + PackedVertex { + x: 0.0, y: 0.0, + color: PackedColor { r: 255, g: 255, b: 255, a: 255 }, + u: 0.0, v: 0.0, + mu: 0, mv: 0, + matrix_index: 0, + clip_in_rect_index: 0, + clip_out_rect_index: 0, + tile_params_index: 0, + }, + PackedVertex { + x: 1.0, y: 0.0, + color: PackedColor { r: 255, g: 255, b: 255, a: 255 }, + u: 0.0, v: 0.0, + mu: 0, mv: 0, + matrix_index: 0, + clip_in_rect_index: 0, + clip_out_rect_index: 0, + tile_params_index: 0, + }, + PackedVertex { + x: 1.0, y: 1.0, + color: PackedColor { r: 255, g: 255, b: 255, a: 255 }, + u: 0.0, v: 0.0, + mu: 0, mv: 0, + matrix_index: 0, + clip_in_rect_index: 0, + clip_out_rect_index: 0, + tile_params_index: 0, + }, + PackedVertex { + x: 0.0, y: 0.0, + color: PackedColor { r: 255, g: 255, b: 255, a: 255 }, + u: 0.0, v: 0.0, + mu: 0, mv: 0, + matrix_index: 0, + clip_in_rect_index: 0, + clip_out_rect_index: 0, + tile_params_index: 0, + }, + PackedVertex { + x: 1.0, y: 1.0, + color: PackedColor { r: 255, g: 255, b: 255, a: 255 }, + u: 0.0, v: 0.0, + mu: 0, mv: 0, + matrix_index: 0, + clip_in_rect_index: 0, + clip_out_rect_index: 0, + tile_params_index: 0, + }, + PackedVertex { + x: 0.0, y: 1.0, + color: PackedColor { r: 255, g: 255, b: 255, a: 255 }, + u: 0.0, v: 0.0, + mu: 0, mv: 0, + matrix_index: 0, + clip_in_rect_index: 0, + clip_out_rect_index: 0, + tile_params_index: 0, + }, +]; + lazy_static! { pub static ref MAX_TEXTURE_SIZE: gl::GLint = { gl::get_integer_v(gl::MAX_TEXTURE_SIZE) @@ -53,7 +116,8 @@ pub enum TextureFilter { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum VertexFormat { - Batch, + Triangles, + Rectangles, DebugFont, DebugColor, RasterOp, @@ -64,97 +128,201 @@ pub trait FileWatcherHandler : Send { } impl VertexFormat { - fn bind(&self) { + fn bind(&self, main: VBOId, aux: Option, offset: gl::GLuint) { + main.bind(); + match *self { VertexFormat::DebugFont => { gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint); - gl::enable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint); - gl::enable_vertex_attrib_array(VertexAttribute::ColorTexCoord as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::ColorRectTL as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectTop as + gl::GLuint); - let vertex_stride = mem::size_of::() as gl::GLint; + self.set_divisors(0); + + let vertex_stride = mem::size_of::() as gl::GLuint; gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint, 2, gl::FLOAT, false, - vertex_stride, - 0); - gl::vertex_attrib_pointer(VertexAttribute::Color as gl::GLuint, + vertex_stride as gl::GLint, + 0 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::ColorRectTL as gl::GLuint, 4, gl::UNSIGNED_BYTE, true, - vertex_stride, - 8); - gl::vertex_attrib_pointer(VertexAttribute::ColorTexCoord as gl::GLuint, + vertex_stride as gl::GLint, + 8 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::ColorTexCoordRectTop as gl::GLuint, 2, gl::FLOAT, false, - vertex_stride, - 12); + vertex_stride as gl::GLint, + 12 + vertex_stride * offset); } VertexFormat::DebugColor => { gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint); - gl::enable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::ColorRectTL as gl::GLuint); - let vertex_stride = mem::size_of::() as gl::GLint; + self.set_divisors(0); + + let vertex_stride = mem::size_of::() as gl::GLuint; gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint, 2, gl::FLOAT, false, - vertex_stride, - 0); - gl::vertex_attrib_pointer(VertexAttribute::Color as gl::GLuint, + vertex_stride as gl::GLint, + 0 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::ColorRectTL as gl::GLuint, 4, gl::UNSIGNED_BYTE, true, - vertex_stride, - 8); + vertex_stride as gl::GLint, + 8 + vertex_stride * offset); } - VertexFormat::Batch => { + VertexFormat::Rectangles => { gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint); - gl::enable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint); - gl::enable_vertex_attrib_array(VertexAttribute::ColorTexCoord as gl::GLuint); - gl::enable_vertex_attrib_array(VertexAttribute::MaskTexCoord as gl::GLuint); - gl::enable_vertex_attrib_array(VertexAttribute::Misc as gl::GLuint); - let vertex_stride = mem::size_of::() as gl::GLint; + let vertex_stride = mem::size_of::() as gl::GLuint; gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint, 2, gl::FLOAT, false, - vertex_stride, + vertex_stride as gl::GLint, 0); - gl::vertex_attrib_pointer(VertexAttribute::Color as gl::GLuint, + + aux.as_ref().unwrap().bind(); + + gl::enable_vertex_attrib_array(VertexAttribute::PositionRect as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::ColorRectTL as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::ColorRectTR as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::ColorRectBR as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::ColorRectBL as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectTop as + gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectBottom as + gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::MaskTexCoordRectTop as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::MaskTexCoordRectBottom as + gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::Misc as gl::GLuint); + + self.set_divisors(1); + + let vertex_stride = mem::size_of::() as gl::GLuint; + + gl::vertex_attrib_pointer(VertexAttribute::PositionRect as gl::GLuint, + 4, + gl::FLOAT, + false, + vertex_stride as gl::GLint, + 0 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::ColorRectTL as gl::GLuint, 4, gl::UNSIGNED_BYTE, false, - vertex_stride, - 8); - gl::vertex_attrib_pointer(VertexAttribute::ColorTexCoord as gl::GLuint, + vertex_stride as gl::GLint, + 16 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::ColorRectTR as gl::GLuint, + 4, + gl::UNSIGNED_BYTE, + false, + vertex_stride as gl::GLint, + 20 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::ColorRectBR as gl::GLuint, + 4, + gl::UNSIGNED_BYTE, + false, + vertex_stride as gl::GLint, + 24 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::ColorRectBL as gl::GLuint, + 4, + gl::UNSIGNED_BYTE, + false, + vertex_stride as gl::GLint, + 28 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::ColorTexCoordRectTop as gl::GLuint, + 4, + gl::FLOAT, + false, + vertex_stride as gl::GLint, + 32 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::ColorTexCoordRectBottom as gl::GLuint, + 4, + gl::FLOAT, + false, + vertex_stride as gl::GLint, + 48 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::MaskTexCoordRectTop as gl::GLuint, + 4, + gl::UNSIGNED_SHORT, + false, + vertex_stride as gl::GLint, + 64 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::MaskTexCoordRectBottom as gl::GLuint, + 4, + gl::UNSIGNED_SHORT, + false, + vertex_stride as gl::GLint, + 72 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::Misc as gl::GLuint, + 4, + gl::UNSIGNED_BYTE, + false, + vertex_stride as gl::GLint, + 80 + vertex_stride * offset); + } + VertexFormat::Triangles => { + gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::ColorRectTL as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectTop as + gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::MaskTexCoordRectTop as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::Misc as gl::GLuint); + + self.set_divisors(0); + + let vertex_stride = mem::size_of::() as gl::GLuint; + + gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint, 2, gl::FLOAT, false, - vertex_stride, - 12); - gl::vertex_attrib_pointer(VertexAttribute::MaskTexCoord as gl::GLuint, + vertex_stride as gl::GLint, + 0 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::ColorRectTL as gl::GLuint, + 4, + gl::UNSIGNED_BYTE, + false, + vertex_stride as gl::GLint, + 8 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::ColorTexCoordRectTop as gl::GLuint, + 2, + gl::FLOAT, + false, + vertex_stride as gl::GLint, + 12 + vertex_stride * offset); + gl::vertex_attrib_pointer(VertexAttribute::MaskTexCoordRectTop as gl::GLuint, 2, gl::UNSIGNED_SHORT, false, - vertex_stride, - 20); + vertex_stride as gl::GLint, + 20 + vertex_stride * offset); gl::vertex_attrib_pointer(VertexAttribute::Misc as gl::GLuint, 4, gl::UNSIGNED_BYTE, false, - vertex_stride, - 24); + vertex_stride as gl::GLint, + 24 + vertex_stride * offset); } VertexFormat::RasterOp => { gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint); - gl::enable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint); - gl::enable_vertex_attrib_array(VertexAttribute::ColorTexCoord as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::ColorRectTL as gl::GLuint); + gl::enable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectTop as + gl::GLuint); gl::enable_vertex_attrib_array(VertexAttribute::BorderRadii as gl::GLuint); gl::enable_vertex_attrib_array(VertexAttribute::BorderPosition as gl::GLuint); gl::enable_vertex_attrib_array(VertexAttribute::BlurRadius as gl::GLuint); @@ -162,61 +330,64 @@ impl VertexFormat { gl::enable_vertex_attrib_array(VertexAttribute::SourceTextureSize as gl::GLuint); gl::enable_vertex_attrib_array(VertexAttribute::Misc as gl::GLuint); - let vertex_stride = mem::size_of::() as gl::GLint; + gl::vertex_attrib_divisor(VertexAttribute::Misc as gl::GLuint, 0); + + let vertex_stride = mem::size_of::() as + gl::GLuint; gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint, 2, gl::FLOAT, false, - vertex_stride, + vertex_stride as gl::GLint, 0); - gl::vertex_attrib_pointer(VertexAttribute::Color as gl::GLuint, + gl::vertex_attrib_pointer(VertexAttribute::ColorRectTL as gl::GLuint, 4, gl::UNSIGNED_BYTE, true, - vertex_stride, + vertex_stride as gl::GLint, 8); - gl::vertex_attrib_pointer(VertexAttribute::ColorTexCoord as gl::GLuint, + gl::vertex_attrib_pointer(VertexAttribute::ColorTexCoordRectTop as gl::GLuint, 2, gl::UNSIGNED_SHORT, true, - vertex_stride, + vertex_stride as gl::GLint, 12); gl::vertex_attrib_pointer(VertexAttribute::BorderRadii as gl::GLuint, 4, gl::FLOAT, false, - vertex_stride, + vertex_stride as gl::GLint, 16); gl::vertex_attrib_pointer(VertexAttribute::BorderPosition as gl::GLuint, 4, gl::FLOAT, false, - vertex_stride, + vertex_stride as gl::GLint, 32); gl::vertex_attrib_pointer(VertexAttribute::DestTextureSize as gl::GLuint, 2, gl::FLOAT, false, - vertex_stride, + vertex_stride as gl::GLint, 48); gl::vertex_attrib_pointer(VertexAttribute::SourceTextureSize as gl::GLuint, 2, gl::FLOAT, false, - vertex_stride, + vertex_stride as gl::GLint, 56); gl::vertex_attrib_pointer(VertexAttribute::BlurRadius as gl::GLuint, 1, gl::FLOAT, false, - vertex_stride, + vertex_stride as gl::GLint, 64); gl::vertex_attrib_pointer(VertexAttribute::Misc as gl::GLuint, 4, gl::UNSIGNED_BYTE, false, - vertex_stride, + vertex_stride as gl::GLint, 68); } } @@ -228,24 +399,64 @@ impl VertexFormat { match *self { VertexFormat::DebugFont => { gl::disable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint); - gl::disable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint); - gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoord as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectTL as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectTR as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectBR as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectBL as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectTop as + gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectBottom as + gl::GLuint); } VertexFormat::DebugColor => { gl::disable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint); - gl::disable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectTL as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectTR as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectBR as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectBL as gl::GLuint); + } + VertexFormat::Rectangles => { + gl::disable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectTL as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectTR as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectBR as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectBL as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectTop as + gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectBottom as + gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::MaskTexCoordRectTop as + gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::MaskTexCoordRectBottom as + gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::Misc as gl::GLuint); } - VertexFormat::Batch => { + VertexFormat::Triangles => { gl::disable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint); - gl::disable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint); - gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoord as gl::GLuint); - gl::disable_vertex_attrib_array(VertexAttribute::MaskTexCoord as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectTL as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectTR as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectBR as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectBL as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectTop as + gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectBottom as + gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::MaskTexCoordRectTop as + gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::MaskTexCoordRectBottom as + gl::GLuint); gl::disable_vertex_attrib_array(VertexAttribute::Misc as gl::GLuint); } VertexFormat::RasterOp => { gl::disable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint); - gl::disable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint); - gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoord as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectTL as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectTR as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectBR as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectBL as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectTop as + gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectBottom as + gl::GLuint); gl::disable_vertex_attrib_array(VertexAttribute::BorderRadii as gl::GLuint); gl::disable_vertex_attrib_array(VertexAttribute::BorderPosition as gl::GLuint); gl::disable_vertex_attrib_array(VertexAttribute::BlurRadius as gl::GLuint); @@ -255,6 +466,23 @@ impl VertexFormat { } } } + + #[cfg(any(target_os = "android", target_os = "gonk"))] + fn set_divisors(&self, _: u32) {} + + #[cfg(not(any(target_os = "android", target_os = "gonk")))] + fn set_divisors(&self, divisor: u32) { + gl::vertex_attrib_divisor(VertexAttribute::PositionRect as gl::GLuint, divisor); + gl::vertex_attrib_divisor(VertexAttribute::ColorRectTL as gl::GLuint, divisor); + gl::vertex_attrib_divisor(VertexAttribute::ColorRectTR as gl::GLuint, divisor); + gl::vertex_attrib_divisor(VertexAttribute::ColorRectBR as gl::GLuint, divisor); + gl::vertex_attrib_divisor(VertexAttribute::ColorRectBL as gl::GLuint, divisor); + gl::vertex_attrib_divisor(VertexAttribute::ColorTexCoordRectTop as gl::GLuint, divisor); + gl::vertex_attrib_divisor(VertexAttribute::ColorTexCoordRectBottom as gl::GLuint, divisor); + gl::vertex_attrib_divisor(VertexAttribute::MaskTexCoordRectTop as gl::GLuint, divisor); + gl::vertex_attrib_divisor(VertexAttribute::MaskTexCoordRectBottom as gl::GLuint, divisor); + gl::vertex_attrib_divisor(VertexAttribute::Misc as gl::GLuint, divisor); + } } impl TextureId { @@ -332,18 +560,42 @@ impl Program { gl::attach_shader(self.id, fs_id); gl::bind_attrib_location(self.id, VertexAttribute::Position as gl::GLuint, "aPosition"); - gl::bind_attrib_location(self.id, VertexAttribute::Color as gl::GLuint, "aColor"); gl::bind_attrib_location(self.id, - VertexAttribute::ColorTexCoord as gl::GLuint, - "aColorTexCoord"); + VertexAttribute::PositionRect as gl::GLuint, + "aPositionRect"); + gl::bind_attrib_location(self.id, + VertexAttribute::ColorRectTL as gl::GLuint, + "aColorRectTL"); + gl::bind_attrib_location(self.id, + VertexAttribute::ColorRectTR as gl::GLuint, + "aColorRectTR"); + gl::bind_attrib_location(self.id, + VertexAttribute::ColorRectBR as gl::GLuint, + "aColorRectBR"); + gl::bind_attrib_location(self.id, + VertexAttribute::ColorRectBL as gl::GLuint, + "aColorRectBL"); + gl::bind_attrib_location(self.id, + VertexAttribute::ColorTexCoordRectTop as gl::GLuint, + "aColorTexCoordRectTop"); + gl::bind_attrib_location(self.id, + VertexAttribute::MaskTexCoordRectTop as gl::GLuint, + "aMaskTexCoordRectTop"); gl::bind_attrib_location(self.id, - VertexAttribute::MaskTexCoord as gl::GLuint, - "aMaskTexCoord"); - gl::bind_attrib_location(self.id, VertexAttribute::BorderRadii as gl::GLuint, "aBorderRadii"); + VertexAttribute::ColorTexCoordRectBottom as gl::GLuint, + "aColorTexCoordRectBottom"); + gl::bind_attrib_location(self.id, + VertexAttribute::MaskTexCoordRectBottom as gl::GLuint, + "aMaskTexCoordRectBottom"); + gl::bind_attrib_location(self.id, + VertexAttribute::BorderRadii as gl::GLuint, + "aBorderRadii"); gl::bind_attrib_location(self.id, VertexAttribute::BorderPosition as gl::GLuint, "aBorderPosition"); - gl::bind_attrib_location(self.id, VertexAttribute::BlurRadius as gl::GLuint, "aBlurRadius"); + gl::bind_attrib_location(self.id, + VertexAttribute::BlurRadius as gl::GLuint, + "aBlurRadius"); gl::bind_attrib_location(self.id, VertexAttribute::DestTextureSize as gl::GLuint, "aDestTextureSize"); @@ -376,17 +628,24 @@ impl Drop for Program { struct VAO { id: gl::GLuint, vertex_format: VertexFormat, - vbo_id: VBOId, + main_vbo_id: VBOId, + aux_vbo_id: Option, ibo_id: IBOId, } #[cfg(any(target_os = "android", target_os = "gonk"))] impl Drop for VAO { fn drop(&mut self) { - // todo(gw): maybe make these there own type with hashmap? - let VBOId(vbo_id) = self.vbo_id; + // In the case of a rect batch, the main VBO is the shared quad VBO, so keep that around. + if self.vertex_format != VertexFormat::Rectangles { + gl::delete_buffers(&[self.main_vbo_id.0]); + } + if let Some(VBOId(aux_vbo_id)) = self.aux_vbo_id { + gl::delete_buffers(&[aux_vbo_id]); + } + + // todo(gw): maybe make these their own type with hashmap? let IBOId(ibo_id) = self.ibo_id; - gl::delete_buffers(&[vbo_id]); gl::delete_buffers(&[ibo_id]); } } @@ -396,10 +655,16 @@ impl Drop for VAO { fn drop(&mut self) { gl::delete_vertex_arrays(&[self.id]); - // todo(gw): maybe make these there own type with hashmap? - let VBOId(vbo_id) = self.vbo_id; + // In the case of a rect batch, the main VBO is the shared quad VBO, so keep that around. + if self.vertex_format != VertexFormat::Rectangles { + gl::delete_buffers(&[self.main_vbo_id.0]); + } + if let Some(VBOId(aux_vbo_id)) = self.aux_vbo_id { + gl::delete_buffers(&[aux_vbo_id]); + } + + // todo(gw): maybe make these their own type with hashmap? let IBOId(ibo_id) = self.ibo_id; - gl::delete_buffers(&[vbo_id]); gl::delete_buffers(&[ibo_id]); } } @@ -417,7 +682,7 @@ pub struct VAOId(gl::GLuint); pub struct FBOId(gl::GLuint); #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] -struct VBOId(gl::GLuint); +pub struct VBOId(gl::GLuint); #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] struct IBOId(gl::GLuint); @@ -1183,9 +1448,14 @@ impl Device { fn clear_vertex_array(&mut self) { debug_assert!(self.inside_frame); gl::disable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint); - gl::disable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint); - gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoord as gl::GLuint); - gl::disable_vertex_attrib_array(VertexAttribute::MaskTexCoord as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectTL as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectTR as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectBR as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorRectBL as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectTop as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectBottom as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::MaskTexCoordRectTop as gl::GLuint); + gl::disable_vertex_attrib_array(VertexAttribute::MaskTexCoordRectBottom as gl::GLuint); gl::disable_vertex_attrib_array(VertexAttribute::BorderRadii as gl::GLuint); gl::disable_vertex_attrib_array(VertexAttribute::BorderPosition as gl::GLuint); gl::disable_vertex_attrib_array(VertexAttribute::BlurRadius as gl::GLuint); @@ -1218,88 +1488,169 @@ impl Device { let vao = self.vaos.get(&vao_id).unwrap(); self.bound_vao = vao_id; - vao.vbo_id.bind(); vao.ibo_id.bind(); - vao.vertex_format.bind(); + vao.vertex_format.bind(vao.main_vbo_id, vao.aux_vbo_id, 0); } } #[cfg(any(target_os = "android", target_os = "gonk"))] - pub fn create_vao(&mut self, format: VertexFormat) -> VAOId { + fn create_vao_with_vbos(&mut self, + format: VertexFormat, + main_vbo_id: VBOId, + aux_vbo_id: Option, + ibo_id: IBOId, + _: u32) + -> VAOId { debug_assert!(self.inside_frame); let vao_id = self.next_vao_id; self.next_vao_id += 1; - let buffer_ids = gl::gen_buffers(2); - let vbo_id = buffer_ids[0]; - let ibo_id = buffer_ids[1]; - - let vbo_id = VBOId(vbo_id); - let ibo_id = IBOId(ibo_id); + format.bind(main_vbo_id, aux_vbo_id, 0); let vao = VAO { id: vao_id, vertex_format: format, - vbo_id: vbo_id, + main_vbo_id: main_vbo_id, + aux_vbo_id: aux_vbo_id, ibo_id: ibo_id, }; let vao_id = VAOId(vao_id); - debug_assert!(self.vaos.contains_key(&vao_id) == false); + debug_assert!(!self.vaos.contains_key(&vao_id)); self.vaos.insert(vao_id, vao); vao_id } - #[cfg(not(any(target_os = "android", target_os = "gonk")))] - pub fn create_vao(&mut self, format: VertexFormat) -> VAOId { + #[cfg(any(target_os = "android", target_os = "gonk"))] + pub fn create_vao(&mut self, format: VertexFormat, quad_vertex_buffer: Option) + -> VAOId { debug_assert!(self.inside_frame); - let vao_ids = gl::gen_vertex_arrays(1); let buffer_ids = gl::gen_buffers(2); + let ibo_id = IBOId(buffer_ids[0]); + let (main_vbo_id, aux_vbo_id) = if format == VertexFormat::Rectangles { + (quad_vertex_buffer.expect("A quad vertex buffer must be supplied to `create_vao()` if + we are to render rectangles!"), + Some(VBOId(buffer_ids[1]))) + } else { + (VBOId(buffer_ids[1]), None) + }; - let vbo_id = buffer_ids[0]; - let ibo_id = buffer_ids[1]; + self.create_vao_with_vbos(format, main_vbo_id, aux_vbo_id, ibo_id, 0) + } + + #[cfg(not(any(target_os = "android", target_os = "gonk")))] + fn create_vao_with_vbos(&mut self, + format: VertexFormat, + main_vbo_id: VBOId, + aux_vbo_id: Option, + ibo_id: IBOId, + offset: gl::GLuint) + -> VAOId { + debug_assert!(self.inside_frame); + + let vao_ids = gl::gen_vertex_arrays(1); let vao_id = vao_ids[0]; gl::bind_vertex_array(vao_id); - gl::bind_buffer(gl::ARRAY_BUFFER, vbo_id); - gl::bind_buffer(gl::ELEMENT_ARRAY_BUFFER, ibo_id); - let vbo_id = VBOId(vbo_id); - let ibo_id = IBOId(ibo_id); + format.bind(main_vbo_id, aux_vbo_id, offset); let vao = VAO { id: vao_id, vertex_format: format, - vbo_id: vbo_id, + main_vbo_id: main_vbo_id, + aux_vbo_id: aux_vbo_id, ibo_id: ibo_id, }; - vao.vertex_format.bind(); - gl::bind_vertex_array(0); let vao_id = VAOId(vao_id); - debug_assert!(self.vaos.contains_key(&vao_id) == false); + debug_assert!(!self.vaos.contains_key(&vao_id)); self.vaos.insert(vao_id, vao); vao_id } - pub fn update_vao_vertices(&mut self, - vao_id: VAOId, - vertices: &[V], - usage_hint: VertexUsageHint) { + #[cfg(not(any(target_os = "android", target_os = "gonk")))] + pub fn create_vao(&mut self, format: VertexFormat, quad_vertex_buffer: Option) + -> VAOId { + debug_assert!(self.inside_frame); + + let buffer_ids = gl::gen_buffers(2); + let ibo_id = IBOId(buffer_ids[0]); + let (main_vbo_id, aux_vbo_id) = if format == VertexFormat::Rectangles { + (quad_vertex_buffer.expect("A quad vertex buffer must be supplied to `create_vao()` if + we are to render rectangles!"), + Some(VBOId(buffer_ids[1]))) + } else { + (VBOId(buffer_ids[1]), None) + }; + + self.create_vao_with_vbos(format, main_vbo_id, aux_vbo_id, ibo_id, 0) + } + + #[inline(never)] + pub fn create_similar_vao(&mut self, + format: VertexFormat, + source_vao_id: VAOId, + offset: gl::GLuint) + -> VAOId { + let &VAO { + main_vbo_id, + aux_vbo_id, + ibo_id, + .. + } = self.vaos.get(&source_vao_id).expect("Bad VAO ID in `create_similar_vao()`!"); + self.create_vao_with_vbos(format, main_vbo_id, aux_vbo_id, ibo_id, offset) + } + + #[cfg(any(target_os = "android", target_os = "gonk"))] + pub fn create_quad_vertex_buffer(&mut self) -> VBOId { + let buffer_id = VBOId(gl::gen_buffers(1)[0]); + buffer_id.bind(); + let mut buffer: Vec<_> = + (0..0x10000).flat_map(|_| QUAD_VERTICES.iter().cloned()).collect(); + gl::buffer_data(gl::ARRAY_BUFFER, &buffer[..], gl::STATIC_DRAW); + buffer_id + } + + #[cfg(not(any(target_os = "android", target_os = "gonk")))] + pub fn create_quad_vertex_buffer(&mut self) -> VBOId { + let buffer_id = VBOId(gl::gen_buffers(1)[0]); + buffer_id.bind(); + gl::buffer_data(gl::ARRAY_BUFFER, &QUAD_VERTICES, gl::STATIC_DRAW); + buffer_id + } + + pub fn update_vao_main_vertices(&mut self, + vao_id: VAOId, + vertices: &[V], + usage_hint: VertexUsageHint) { debug_assert!(self.inside_frame); let vao = self.vaos.get(&vao_id).unwrap(); debug_assert!(self.bound_vao == vao_id); - vao.vbo_id.bind(); + vao.main_vbo_id.bind(); + gl::buffer_data(gl::ARRAY_BUFFER, &vertices, usage_hint.to_gl()); + } + + pub fn update_vao_aux_vertices(&mut self, + vao_id: VAOId, + vertices: &[V], + usage_hint: VertexUsageHint) { + debug_assert!(self.inside_frame); + + let vao = self.vaos.get(&vao_id).unwrap(); + debug_assert!(self.bound_vao == vao_id); + + vao.aux_vbo_id.as_ref().unwrap().bind(); gl::buffer_data(gl::ARRAY_BUFFER, &vertices, usage_hint.to_gl()); } @@ -1339,6 +1690,24 @@ impl Device { vertex_count); } + #[cfg(any(target_os = "android", target_os = "gonk"))] + pub fn draw_triangles_instanced_u16(&mut self, + first_vertex: i32, + index_count: i32, + instance_count: i32) { + debug_assert!(self.inside_frame); + gl::draw_arrays(gl::TRIANGLES, first_vertex * index_count, instance_count * index_count); + } + + #[cfg(not(any(target_os = "android", target_os = "gonk")))] + pub fn draw_triangles_instanced_u16(&mut self, + first_vertex: i32, + index_count: i32, + instance_count: i32) { + debug_assert!(self.inside_frame); + gl::draw_arrays_instanced(gl::TRIANGLES, first_vertex as i32, index_count, instance_count); + } + pub fn delete_vao(&mut self, vao_id: VAOId) { self.vaos.remove(&vao_id).expect(&format!("unable to remove vao {:?}", vao_id)); if self.bound_vao == vao_id { diff --git a/src/frame.rs b/src/frame.rs index e155f0e85c..cc428bc1a1 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -194,8 +194,8 @@ impl RenderTarget { vertex_buffer_id: vertex_buffer_id, color_texture_id: batch.color_texture_id, mask_texture_id: batch.mask_texture_id, - first_vertex: batch.first_vertex, - index_count: batch.index_count, + first_instance: batch.first_instance, + instance_count: batch.instance_count, }); } } @@ -1123,8 +1123,7 @@ impl Frame { self.pending_updates.push(BatchUpdate { id: vertex_buffer.id, - op: BatchUpdateOp::Create(vertex_buffer.vertices, - vertex_buffer.indices), + op: BatchUpdateOp::Create(vertex_buffer.vertices), }); compiled_node.vertex_buffer_id = Some(vertex_buffer.id); diff --git a/src/internal_types.rs b/src/internal_types.rs index 858a1e16c8..e55575eb17 100644 --- a/src/internal_types.rs +++ b/src/internal_types.rs @@ -47,9 +47,15 @@ pub enum TextureSampler { pub enum VertexAttribute { Position, - Color, - ColorTexCoord, - MaskTexCoord, + PositionRect, + ColorRectTL, + ColorRectTR, + ColorRectBR, + ColorRectBL, + ColorTexCoordRectTop, + MaskTexCoordRectTop, + ColorTexCoordRectBottom, + MaskTexCoordRectBottom, BorderRadii, BorderPosition, BlurRadius, @@ -126,6 +132,92 @@ impl WorkVertex { } } +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum PackedVertexColorMode { + Gradient, + BorderCorner, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct PackedVertexForQuad { + pub x: f32, + pub y: f32, + pub width: f32, + pub height: f32, + pub color_tl: PackedColor, + pub color_tr: PackedColor, + pub color_br: PackedColor, + pub color_bl: PackedColor, + pub u_tl: f32, + pub v_tl: f32, + pub u_tr: f32, + pub v_tr: f32, + pub u_br: f32, + pub v_br: f32, + pub u_bl: f32, + pub v_bl: f32, + pub mu_tl: u16, + pub mv_tl: u16, + pub mu_tr: u16, + pub mv_tr: u16, + pub mu_br: u16, + pub mv_br: u16, + pub mu_bl: u16, + pub mv_bl: u16, + pub matrix_index: u8, + pub clip_in_rect_index: u8, + pub clip_out_rect_index: u8, + pub tile_params_index: u8, +} + +impl PackedVertexForQuad { + pub fn new(position: &Rect, + colors: &[ColorF; 4], + uv: &RectUv, + muv: &RectUv, + color_mode: PackedVertexColorMode) + -> PackedVertexForQuad { + return PackedVertexForQuad { + x: position.origin.x, + y: position.origin.y, + width: position.size.width, + height: position.size.height, + color_tl: PackedColor::from_color(&colors[0]), + color_tr: PackedColor::from_color(&colors[1]), + color_br: PackedColor::from_color(&colors[2]), + color_bl: PackedColor::from_color(&colors[3]), + u_tl: uv.top_left.x, + v_tl: uv.top_left.y, + u_tr: uv.top_right.x, + v_tr: uv.top_right.y, + u_bl: uv.bottom_left.x, + v_bl: uv.bottom_left.y, + u_br: uv.bottom_right.x, + v_br: uv.bottom_right.y, + mu_tl: scale_muv_value(muv.top_left.x), + mv_tl: scale_muv_value(muv.top_left.y), + mu_tr: scale_muv_value(muv.top_right.x), + mv_tr: scale_muv_value(muv.top_right.y), + mu_bl: scale_muv_value(muv.bottom_left.x), + mv_bl: scale_muv_value(muv.bottom_left.y), + mu_br: scale_muv_value(muv.bottom_right.x), + mv_br: scale_muv_value(muv.bottom_right.y), + matrix_index: 0, + clip_in_rect_index: 0, + clip_out_rect_index: 0, + tile_params_index: match color_mode { + PackedVertexColorMode::Gradient => 0x00, + PackedVertexColorMode::BorderCorner => 0x80, + }, + }; + + fn scale_muv_value(value: f32) -> u16 { + (value * UV_FLOAT_TO_FIXED) as u16 + } + } +} + #[derive(Debug, Clone, Copy)] #[repr(C)] pub struct PackedVertex { @@ -188,14 +280,6 @@ impl PackedVertex { tile_params_index: 0, } } - - pub fn from_points(position: &Point2D, - color: &ColorF, - uv: &Point2D, - muv: &Point2D) - -> PackedVertex { - PackedVertex::from_components(position.x, position.y, color, uv.x, uv.y, muv.x, muv.y) - } } #[derive(Debug)] @@ -287,7 +371,7 @@ impl TextureUpdateList { } pub enum BatchUpdateOp { - Create(Vec, Vec), + Create(Vec), Destroy, } @@ -330,8 +414,8 @@ pub struct DrawCall { pub vertex_buffer_id: VertexBufferId, pub color_texture_id: TextureId, pub mask_texture_id: TextureId, - pub first_vertex: u32, - pub index_count: u16, + pub first_instance: u32, + pub instance_count: u32, } #[derive(Clone, Debug)] @@ -484,12 +568,6 @@ impl FreeListItem for DrawList { #[derive(Clone, Copy, Debug, Ord, PartialOrd, PartialEq, Eq)] pub struct DrawListItemIndex(pub u32); -#[derive(Debug, Copy, Clone)] -pub enum Primitive { - Triangles, - Rectangles, // 4 vertices per rect -} - #[derive(Debug)] pub struct BatchList { pub batches: Vec, diff --git a/src/renderer.rs b/src/renderer.rs index c8592d1f63..ce11f26382 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,7 +1,7 @@ use batch::{RasterBatch, VertexBufferId}; use debug_render::DebugRenderer; use device::{Device, ProgramId, TextureId, UniformLocation, VertexFormat}; -use device::{TextureFilter, VAOId, VertexUsageHint, FileWatcherHandler}; +use device::{TextureFilter, VAOId, VBOId, VertexUsageHint, FileWatcherHandler}; use euclid::{Rect, Matrix4, Point2D, Size2D}; use fnv::FnvHasher; use gleam::gl; @@ -46,6 +46,7 @@ const GL_BLEND_MAX: gl::GLuint = gl::MAX; #[cfg(any(target_os = "android", target_os = "gonk"))] const GL_BLEND_MAX: gl::GLuint = gl::FUNC_ADD; +#[derive(Clone, Copy)] struct VertexBuffer { vao_id: VAOId, } @@ -107,8 +108,9 @@ pub struct Renderer { pending_shader_updates: Vec, current_frame: Option, device_pixel_ratio: f32, - vertex_buffers: HashMap>, + vertex_buffers: HashMap, DefaultState>, raster_batches: Vec, + quad_vertex_buffer: Option, quad_program_id: ProgramId, u_quad_transform_array: UniformLocation, @@ -239,6 +241,7 @@ impl Renderer { current_frame: None, vertex_buffers: HashMap::with_hash_state(Default::default()), raster_batches: Vec::new(), + quad_vertex_buffer: None, pending_texture_updates: Vec::new(), pending_batch_updates: Vec::new(), pending_shader_updates: Vec::new(), @@ -353,24 +356,34 @@ impl Renderer { for update_list in pending_batch_updates.drain(..) { for update in update_list.updates { match update.op { - BatchUpdateOp::Create(vertices, indices) => { - let vao_id = self.device.create_vao(VertexFormat::Batch); + BatchUpdateOp::Create(vertices) => { + if self.quad_vertex_buffer.is_none() { + self.quad_vertex_buffer = Some(self.device.create_quad_vertex_buffer()) + } + + let vao_id = self.device.create_vao(VertexFormat::Rectangles, + self.quad_vertex_buffer); self.device.bind_vao(vao_id); - self.device.update_vao_indices(vao_id, - &indices, - VertexUsageHint::Static); - self.device.update_vao_vertices(vao_id, - &vertices, - VertexUsageHint::Static); + self.device.update_vao_aux_vertices(vao_id, + &vertices, + VertexUsageHint::Static); - self.vertex_buffers.insert(update.id, VertexBuffer { - vao_id: vao_id, - }); + self.vertex_buffers.insert(update.id, vec![ + VertexBufferAndOffset { + buffer: VertexBuffer { + vao_id: vao_id, + }, + offset: 0, + } + ]); } BatchUpdateOp::Destroy => { - let vertex_buffer = self.vertex_buffers.remove(&update.id).unwrap(); - self.device.delete_vao(vertex_buffer.vao_id); + let vertex_buffers_and_offsets = + self.vertex_buffers.remove(&update.id).unwrap(); + for vertex_buffer_and_offset in vertex_buffers_and_offsets.into_iter() { + self.device.delete_vao(vertex_buffer_and_offset.buffer.vao_id); + } } } } @@ -903,15 +916,18 @@ impl Renderer { } fn perform_gl_texture_cache_update(&mut self, batch: RasterBatch) { - let vao_id = self.device.create_vao(VertexFormat::RasterOp); + let vao_id = self.device.create_vao(VertexFormat::RasterOp, None); self.device.bind_vao(vao_id); self.device.update_vao_indices(vao_id, &batch.indices[..], VertexUsageHint::Dynamic); - self.device.update_vao_vertices(vao_id, &batch.vertices[..], VertexUsageHint::Dynamic); + self.device.update_vao_main_vertices(vao_id, + &batch.vertices[..], + VertexUsageHint::Dynamic); self.profile_counters.vertices.add(batch.indices.len()); self.profile_counters.draw_calls.inc(); + println!("drawing triangles due to GL texture cache update"); self.device.draw_triangles_u16(0, batch.indices.len() as gl::GLint); self.device.delete_vao(vao_id); } @@ -1004,7 +1020,10 @@ impl Renderer { &info.matrix_palette); for draw_call in &info.draw_calls { - let vao_id = self.vertex_buffers[&draw_call.vertex_buffer_id].vao_id; + let vao_id = self.get_or_create_similar_vao_with_offset( + draw_call.vertex_buffer_id, + VertexFormat::Rectangles, + draw_call.first_instance); self.device.bind_vao(vao_id); if draw_call.tile_params.len() > 0 { @@ -1051,12 +1070,10 @@ impl Renderer { mask_size.0 as f32, mask_size.1 as f32); - let index_count = draw_call.index_count as i32; - self.profile_counters.draw_calls.inc(); - self.device.draw_triangles_u16(draw_call.first_vertex as i32, - index_count); + self.device + .draw_triangles_instanced_u16(0, 6, draw_call.instance_count as i32); } } &DrawCommand::CompositeBatch(ref info) => { @@ -1346,6 +1363,34 @@ impl Renderer { } } + fn get_or_create_similar_vao_with_offset(&mut self, + source_vertex_buffer_id: VertexBufferId, + format: VertexFormat, + offset: u32) + -> VAOId { + let source_vertex_buffers_and_offsets = + self.vertex_buffers.get_mut(&source_vertex_buffer_id) + .expect("Didn't find source vertex buffer ID in \ + `get_or_create_similar_vao_with_offset()`!"); + if let Some(vertex_buffer_and_offset) = + source_vertex_buffers_and_offsets.iter().find(|vertex_buffer| { + vertex_buffer.offset == offset + }) { + return vertex_buffer_and_offset.buffer.vao_id + } + + let vao = + self.device.create_similar_vao(format, + source_vertex_buffers_and_offsets[0].buffer.vao_id, + offset); + source_vertex_buffers_and_offsets.push(VertexBufferAndOffset { + buffer: VertexBuffer { + vao_id: vao, + }, + offset: offset, + }); + vao + } } fn draw_simple_triangles(device: &mut Device, @@ -1355,11 +1400,11 @@ fn draw_simple_triangles(device: &mut Device, texture: TextureId) { // TODO(glennw): Don't re-create this VAO all the time. Create it once and set positions // via uniforms. - let vao_id = device.create_vao(VertexFormat::Batch); + let vao_id = device.create_vao(VertexFormat::Triangles, None); device.bind_color_texture(texture); device.bind_vao(vao_id); device.update_vao_indices(vao_id, &indices[..], VertexUsageHint::Dynamic); - device.update_vao_vertices(vao_id, &vertices[..], VertexUsageHint::Dynamic); + device.update_vao_main_vertices(vao_id, &vertices[..], VertexUsageHint::Dynamic); profile_counters.vertices.add(indices.len()); profile_counters.draw_calls.inc(); @@ -1368,3 +1413,8 @@ fn draw_simple_triangles(device: &mut Device, device.delete_vao(vao_id); } +struct VertexBufferAndOffset { + buffer: VertexBuffer, + offset: u32, +} +