From a59bfe6b644349083f0409bc7e8295a0e333953f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 8 Jan 2016 18:35:43 -0800 Subject: [PATCH] Use instancing to make VBO data per-rectangle, not per-vertex. Doing this slightly reduces the size of our VBOs and opens the door to performing clipping in the vertex shader. With more clever optimizations, we should be able to shrink the VBO size down even further. This patch includes a fallback for OpenGL ES 2.1. Unfortunately, this fallback increases the size of the VBOs significantly. This could be mitigated in the future, though not without effort. --- res/blend.vs.glsl | 4 +- res/blit.vs.glsl | 4 +- res/blur.vs.glsl | 2 +- res/border.vs.glsl | 2 +- res/box_shadow.vs.glsl | 2 +- res/clear.vs.glsl | 2 +- res/debug_color.vs.glsl | 2 +- res/debug_font.vs.glsl | 4 +- res/es2_common.vs.glsl | 29 +- res/filter.vs.glsl | 4 +- res/gl3_common.vs.glsl | 28 +- res/quad.vs.glsl | 58 +++- src/batch.rs | 150 +++++----- src/batch_builder.rs | 181 ++++-------- src/debug_render.rs | 24 +- src/device.rs | 591 ++++++++++++++++++++++++++++++++-------- src/frame.rs | 7 +- src/internal_types.rs | 118 ++++++-- src/renderer.rs | 98 +++++-- 19 files changed, 895 insertions(+), 415 deletions(-) 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, +} +