diff --git a/webrender/res/prim_shared.glsl b/webrender/res/prim_shared.glsl index 8d44430f68..9ecf0e037c 100644 --- a/webrender/res/prim_shared.glsl +++ b/webrender/res/prim_shared.glsl @@ -106,12 +106,36 @@ varying vec3 vClipMaskUv; flat varying vec4 vLocalBounds; #endif +// TODO(gw): This is here temporarily while we have +// both GPU store and cache. When the GPU +// store code is removed, we can change the +// PrimitiveInstance instance structure to +// use 2x unsigned shorts as vertex attributes +// instead of an int, and encode the UV directly +// in the vertices. +ivec2 get_resource_cache_uv(int address) { + return ivec2(address % WR_MAX_VERTEX_TEXTURE_WIDTH, + address / WR_MAX_VERTEX_TEXTURE_WIDTH); +} + +uniform sampler2D sResourceCache; + +vec4[2] fetch_from_resource_cache_2(int address) { + ivec2 uv = get_resource_cache_uv(address); + return vec4[2]( + texelFetchOffset(sResourceCache, uv, 0, ivec2(0, 0)), + texelFetchOffset(sResourceCache, uv, 0, ivec2(1, 0)) + ); +} + #ifdef WR_VERTEX_SHADER #define VECS_PER_LAYER 9 #define VECS_PER_RENDER_TASK 3 #define VECS_PER_PRIM_HEADER 2 #define VECS_PER_TEXT_RUN 1 +#define VECS_PER_GRADIENT 3 +#define VECS_PER_GRADIENT_STOP 2 uniform sampler2D sLayers; uniform sampler2D sRenderTasks; @@ -119,7 +143,6 @@ uniform sampler2D sRenderTasks; uniform sampler2D sData16; uniform sampler2D sData32; uniform sampler2D sResourceRects; -uniform sampler2D sResourceCache; // Instanced attributes in ivec4 aData0; @@ -144,18 +167,6 @@ vec4[2] fetch_data_2(int index) { ); } -// TODO(gw): This is here temporarily while we have -// both GPU store and cache. When the GPU -// store code is removed, we can change the -// PrimitiveInstance instance structure to -// use 2x unsigned shorts as vertex attributes -// instead of an int, and encode the UV directly -// in the vertices. -ivec2 get_resource_cache_uv(int address) { - return ivec2(address % WR_MAX_VERTEX_TEXTURE_WIDTH, - address / WR_MAX_VERTEX_TEXTURE_WIDTH); -} - vec4[8] fetch_from_resource_cache_8(int address) { ivec2 uv = get_resource_cache_uv(address); return vec4[8]( @@ -189,14 +200,6 @@ vec4[4] fetch_from_resource_cache_4(int address) { ); } -vec4[2] fetch_from_resource_cache_2(int address) { - ivec2 uv = get_resource_cache_uv(address); - return vec4[2]( - texelFetchOffset(sResourceCache, uv, 0, ivec2(0, 0)), - texelFetchOffset(sResourceCache, uv, 0, ivec2(1, 0)) - ); -} - vec4 fetch_from_resource_cache_1(int address) { ivec2 uv = get_resource_cache_uv(address); return texelFetch(sResourceCache, uv, 0); @@ -328,8 +331,8 @@ struct GradientStop { vec4 offset; }; -GradientStop fetch_gradient_stop(int index) { - vec4 data[2] = fetch_data_2(index); +GradientStop fetch_gradient_stop(int address) { + vec4 data[2] = fetch_from_resource_cache_2(address); return GradientStop(data[0], data[1]); } @@ -847,10 +850,8 @@ vec4 dither(vec4 color) { } #endif //WR_FEATURE_DITHERING -vec4 sample_gradient(float offset, float gradient_repeat, float gradient_index, vec2 gradient_size) { - // Modulo the offset if the gradient repeats. We don't need to clamp non-repeating - // gradients because the gradient data texture is bound with CLAMP_TO_EDGE, and the - // first and last color entries are filled with the first and last stop colors +vec4 sample_gradient(int address, float offset, float gradient_repeat) { + // Modulo the offset if the gradient repeats. float x = mix(offset, fract(offset), gradient_repeat); // Calculate the color entry index to use for this offset: @@ -858,22 +859,25 @@ vec4 sample_gradient(float offset, float gradient_repeat, float gradient_index, // offsets from [0, 1) use the color entries in the range of [1, N-1) // offsets >= 1 use the last color entry, N-1 // so transform the range [0, 1) -> [1, N-1) - float gradient_entries = 0.5 * gradient_size.x; - x = x * (gradient_entries - 2.0) + 1.0; + + // TODO(gw): In the future we might consider making the size of the + // LUT vary based on number / distribution of stops in the gradient. + const int GRADIENT_ENTRIES = 128; + x = 1.0 + x * float(GRADIENT_ENTRIES); // Calculate the texel to index into the gradient color entries: // floor(x) is the gradient color entry index // fract(x) is the linear filtering factor between start and end - // so, 2 * floor(x) + 0.5 is the center of the start color - // finally, add floor(x) to interpolate to end - x = 2.0 * floor(x) + 0.5 + fract(x); + int lut_offset = 2 * int(floor(x)); // There is a [start, end] color per entry. + + // Ensure we don't fetch outside the valid range of the LUT. + lut_offset = clamp(lut_offset, 0, 2 * (GRADIENT_ENTRIES + 1)); - // Gradient color entries are encoded with high bits in one row and low bits in the next - // So use linear filtering to mix (gradient_index + 1) with (gradient_index) - float y = gradient_index * 2.0 + 0.5 + 1.0 / 256.0; + // Fetch the start and end color. + vec4 texels[2] = fetch_from_resource_cache_2(address + lut_offset); - // Finally sample and apply dithering - return dither(texture(sGradients, vec2(x, y) / gradient_size)); + // Finally interpolate and apply dithering + return dither(mix(texels[0], texels[1], fract(x))); } // diff --git a/webrender/res/ps_angle_gradient.fs.glsl b/webrender/res/ps_angle_gradient.fs.glsl index e8842c3e82..ea92ebde85 100644 --- a/webrender/res/ps_angle_gradient.fs.glsl +++ b/webrender/res/ps_angle_gradient.fs.glsl @@ -1,3 +1,5 @@ +#line 1 + /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -12,8 +14,7 @@ void main(void) { float offset = dot(pos - vStartPoint, vScaledDir); - oFragColor = sample_gradient(offset, - vGradientRepeat, - vGradientIndex, - vGradientTextureSize); + oFragColor = sample_gradient(vGradientAddress, + offset, + vGradientRepeat); } diff --git a/webrender/res/ps_angle_gradient.glsl b/webrender/res/ps_angle_gradient.glsl index 67ab75f766..3224bdc8ea 100644 --- a/webrender/res/ps_angle_gradient.glsl +++ b/webrender/res/ps_angle_gradient.glsl @@ -2,8 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -flat varying float vGradientIndex; -flat varying vec2 vGradientTextureSize; +flat varying int vGradientAddress; flat varying float vGradientRepeat; flat varying vec2 vScaledDir; diff --git a/webrender/res/ps_angle_gradient.vs.glsl b/webrender/res/ps_angle_gradient.vs.glsl index 7cd03e1146..e564d451a2 100644 --- a/webrender/res/ps_angle_gradient.vs.glsl +++ b/webrender/res/ps_angle_gradient.vs.glsl @@ -26,11 +26,7 @@ void main(void) { vTileSize = gradient.tile_size_repeat.xy; vTileRepeat = gradient.tile_size_repeat.zw; - // V coordinate of gradient row in lookup texture. - vGradientIndex = float(prim.user_data0); - - // The texture size of the lookup texture - vGradientTextureSize = vec2(textureSize(sGradients, 0)); + vGradientAddress = prim.specific_prim_address + VECS_PER_GRADIENT; // Whether to repeat the gradient instead of clamping. vGradientRepeat = float(int(gradient.extend_mode.x) == EXTEND_MODE_REPEAT); diff --git a/webrender/res/ps_gradient.vs.glsl b/webrender/res/ps_gradient.vs.glsl index 670a29030f..9138d69295 100644 --- a/webrender/res/ps_gradient.vs.glsl +++ b/webrender/res/ps_gradient.vs.glsl @@ -9,8 +9,12 @@ void main(void) { vec4 abs_start_end_point = gradient.start_end_point + prim.local_rect.p0.xyxy; - GradientStop g0 = fetch_gradient_stop(prim.user_data0 + 0); - GradientStop g1 = fetch_gradient_stop(prim.user_data0 + 1); + int stop_address = prim.specific_prim_address + + VECS_PER_GRADIENT + + VECS_PER_GRADIENT_STOP * prim.user_data0; + + GradientStop g0 = fetch_gradient_stop(stop_address); + GradientStop g1 = fetch_gradient_stop(stop_address + VECS_PER_GRADIENT_STOP); RectWithSize segment_rect; vec2 axis; diff --git a/webrender/res/ps_radial_gradient.fs.glsl b/webrender/res/ps_radial_gradient.fs.glsl index 531b9e0965..75bdd52d98 100644 --- a/webrender/res/ps_radial_gradient.fs.glsl +++ b/webrender/res/ps_radial_gradient.fs.glsl @@ -49,8 +49,7 @@ void main(void) { } } - oFragColor = sample_gradient(offset, - vGradientRepeat, - vGradientIndex, - vGradientTextureSize); + oFragColor = sample_gradient(vGradientAddress, + offset, + vGradientRepeat); } diff --git a/webrender/res/ps_radial_gradient.glsl b/webrender/res/ps_radial_gradient.glsl index e6700ea156..19c83d46e3 100644 --- a/webrender/res/ps_radial_gradient.glsl +++ b/webrender/res/ps_radial_gradient.glsl @@ -2,8 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -flat varying float vGradientIndex; -flat varying vec2 vGradientTextureSize; +flat varying int vGradientAddress; flat varying float vGradientRepeat; flat varying vec2 vStartCenter; diff --git a/webrender/res/ps_radial_gradient.vs.glsl b/webrender/res/ps_radial_gradient.vs.glsl index b5aa7beedd..3b5800428f 100644 --- a/webrender/res/ps_radial_gradient.vs.glsl +++ b/webrender/res/ps_radial_gradient.vs.glsl @@ -34,11 +34,7 @@ void main(void) { vTileSize.y *= ratio_xy; vTileRepeat.y *= ratio_xy; - // V coordinate of gradient row in lookup texture. - vGradientIndex = float(prim.user_data0); - - // The texture size of the lookup texture - vGradientTextureSize = vec2(textureSize(sGradients, 0)); + vGradientAddress = prim.specific_prim_address + VECS_PER_GRADIENT; // Whether to repeat the gradient instead of clamping. vGradientRepeat = float(int(gradient.start_end_radius_ratio_xy_extend_mode.w) == EXTEND_MODE_REPEAT); diff --git a/webrender/src/device.rs b/webrender/src/device.rs index 8b6d9580f1..fcc81c3065 100644 --- a/webrender/src/device.rs +++ b/webrender/src/device.rs @@ -1569,11 +1569,6 @@ impl Device { self.gl.uniform_1i(u_resource_rects, TextureSampler::ResourceRects as i32); } - let u_gradients = self.gl.get_uniform_location(program.id, "sGradients"); - if u_gradients != -1 { - self.gl.uniform_1i(u_gradients, TextureSampler::Gradients as i32); - } - Ok(()) } diff --git a/webrender/src/frame_builder.rs b/webrender/src/frame_builder.rs index ecf6f82970..a407c47c8b 100644 --- a/webrender/src/frame_builder.rs +++ b/webrender/src/frame_builder.rs @@ -662,9 +662,6 @@ impl FrameBuilder { stops_count: stops_count, extend_mode: extend_mode, reverse_stops: reverse_stops, - cache_dirty: true, - gpu_data_address: GpuStoreAddress(0), - gpu_data_count: 0, gpu_blocks: [ [sp.x, sp.y, ep.x, ep.y].into(), [tile_size.width, tile_size.height, tile_repeat.width, tile_repeat.height].into(), @@ -699,7 +696,6 @@ impl FrameBuilder { let radial_gradient_cpu = RadialGradientPrimitiveCpu { stops_range: stops, extend_mode: extend_mode, - cache_dirty: true, gpu_data_address: GpuStoreAddress(0), gpu_data_count: 0, gpu_blocks: [ @@ -1454,7 +1450,6 @@ impl FrameBuilder { layer_texture_data: self.packed_layers.clone(), render_task_data: render_tasks.render_task_data, gpu_data32: self.prim_store.gpu_data32.build(), - gpu_gradient_data: self.prim_store.gpu_gradient_data.build(), gpu_resource_rects: self.prim_store.gpu_resource_rects.build(), deferred_resolves: deferred_resolves, gpu_cache_updates: Some(gpu_cache_updates), diff --git a/webrender/src/internal_types.rs b/webrender/src/internal_types.rs index 1b9ce2aa7d..b647167e80 100644 --- a/webrender/src/internal_types.rs +++ b/webrender/src/internal_types.rs @@ -48,7 +48,6 @@ pub enum SourceTexture { } const COLOR_FLOAT_TO_FIXED: f32 = 255.0; -const COLOR_FLOAT_TO_FIXED_WIDE: f32 = 65535.0; pub const ANGLE_FLOAT_TO_FIXED: f32 = 65535.0; pub const ORTHO_NEAR_PLANE: f32 = -1000000.0; @@ -72,7 +71,6 @@ pub enum TextureSampler { Layers, RenderTasks, ResourceRects, - Gradients, Dither, } @@ -140,7 +138,6 @@ pub enum ClipAttribute { } // A packed RGBA8 color ordered for vertex data or similar. -// Use PackedTexel instead if intending to upload to a texture. #[derive(Debug, Clone, Copy)] #[repr(C)] @@ -162,37 +159,6 @@ impl PackedColor { } } -// RGBA8 textures currently pack texels in BGRA format for upload. -// PackedTexel abstracts away this difference from PackedColor. - -#[derive(Debug, Clone, Copy)] -#[repr(C)] -pub struct PackedTexel { - pub b: u8, - pub g: u8, - pub r: u8, - pub a: u8, -} - -impl PackedTexel { - pub fn high_bytes(color: &ColorF) -> PackedTexel { - Self::extract_bytes(color, 8) - } - - pub fn low_bytes(color: &ColorF) -> PackedTexel { - Self::extract_bytes(color, 0) - } - - fn extract_bytes(color: &ColorF, shift_by: i32) -> PackedTexel { - PackedTexel { - b: ((0.5 + color.b * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u32 >> shift_by & 0xff) as u8, - g: ((0.5 + color.g * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u32 >> shift_by & 0xff) as u8, - r: ((0.5 + color.r * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u32 >> shift_by & 0xff) as u8, - a: ((0.5 + color.a * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u32 >> shift_by & 0xff) as u8, - } - } -} - #[derive(Debug, Clone, Copy)] #[repr(C)] pub struct PackedVertex { diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index e2e555d6b2..f36acd1203 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -8,9 +8,9 @@ use border::BorderCornerInstance; use euclid::{Size2D}; use gpu_cache::{GpuBlockData, GpuCache, GpuCacheHandle, GpuDataRequest, ToGpuBlocks}; use gpu_store::GpuStoreAddress; -use internal_types::{SourceTexture, PackedTexel}; +use internal_types::SourceTexture; use mask_cache::{ClipMode, ClipSource, MaskCacheInfo}; -use renderer::{VertexDataStore, GradientDataStore, MAX_VERTEX_TEXTURE_WIDTH}; +use renderer::{VertexDataStore, MAX_VERTEX_TEXTURE_WIDTH}; use render_task::{RenderTask, RenderTaskLocation}; use resource_cache::{CacheItem, ImageProperties, ResourceCache}; use std::mem; @@ -23,7 +23,7 @@ use webrender_traits::{device_length, DeviceIntRect, DeviceIntSize}; use webrender_traits::{DeviceRect, DevicePoint, DeviceSize}; use webrender_traits::{LayerRect, LayerSize, LayerPoint, LayoutPoint}; use webrender_traits::{LayerToWorldTransform, GlyphInstance, GlyphOptions}; -use webrender_traits::{ExtendMode, GradientStop, AuxIter, TileOffset}; +use webrender_traits::{ExtendMode, GradientStop, TileOffset}; pub const CLIP_DATA_GPU_SIZE: usize = 5; pub const MASK_DATA_GPU_SIZE: usize = 1; @@ -246,45 +246,36 @@ impl ToGpuBlocks for BoxShadowPrimitiveCpu { } } -#[derive(Debug, Clone)] -#[repr(C)] -pub struct GradientStopGpu { - color: ColorF, - offset: f32, - padding: [f32; 3], -} - #[derive(Debug)] pub struct GradientPrimitiveCpu { pub stops_range: ItemRange, pub stops_count: usize, pub extend_mode: ExtendMode, pub reverse_stops: bool, - pub cache_dirty: bool, - pub gpu_data_address: GpuStoreAddress, - pub gpu_data_count: i32, pub gpu_blocks: [GpuBlockData; 3], } -impl ToGpuBlocks for GradientPrimitiveCpu { - fn write_gpu_blocks(&self, mut request: GpuDataRequest) { +impl GradientPrimitiveCpu { + fn build_gpu_blocks_for_aligned(&self, + display_list: &BuiltDisplayList, + mut request: GpuDataRequest) { request.extend_from_slice(&self.gpu_blocks); - } -} + let src_stops = display_list.get(self.stops_range); -#[derive(Debug)] -pub struct RadialGradientPrimitiveCpu { - pub stops_range: ItemRange, - pub extend_mode: ExtendMode, - pub cache_dirty: bool, - pub gpu_data_address: GpuStoreAddress, - pub gpu_data_count: i32, - pub gpu_blocks: [GpuBlockData; 3], -} + for src in src_stops { + request.push(src.color.premultiplied().into()); + request.push([src.offset, 0.0, 0.0, 0.0].into()); + } + } -impl ToGpuBlocks for RadialGradientPrimitiveCpu { - fn write_gpu_blocks(&self, mut request: GpuDataRequest) { + fn build_gpu_blocks_for_angle_radial(&self, + display_list: &BuiltDisplayList, + mut request: GpuDataRequest) { request.extend_from_slice(&self.gpu_blocks); + + let gradient_builder = GradientGpuBlockBuilder::new(self.stops_range, + display_list); + gradient_builder.build(self.reverse_stops, &mut request); } } @@ -307,47 +298,32 @@ pub const GRADIENT_DATA_SIZE: usize = GRADIENT_DATA_TABLE_SIZE + 2; #[repr(C)] // An entry in a gradient data table representing a segment of the gradient color space. pub struct GradientDataEntry { - pub start_color: PackedTexel, - pub end_color: PackedTexel, -} - -#[repr(C)] -// A table of gradient entries, with two colors per entry, that specify the start and end color -// within the segment of the gradient space represented by that entry. To lookup a gradient result, -// first the entry index is calculated to determine which two colors to interpolate between, then -// the offset within that entry bucket is used to interpolate between the two colors in that entry. -// This layout preserves hard stops, as the end color for a given entry can differ from the start -// color for the following entry, despite them being adjacent. Colors are stored within in BGRA8 -// format for texture upload. This table requires the gradient color stops to be normalized to the -// range [0, 1]. The first and last entries hold the first and last color stop colors respectively, -// while the entries in between hold the interpolated color stop values for the range [0, 1]. -pub struct GradientData { - pub colors_high: [GradientDataEntry; GRADIENT_DATA_SIZE], - pub colors_low: [GradientDataEntry; GRADIENT_DATA_SIZE], + pub start_color: ColorF, + pub end_color: ColorF, } -impl Default for GradientData { - fn default() -> GradientData { - GradientData { - colors_high: unsafe { mem::uninitialized() }, - colors_low: unsafe { mem::uninitialized() } - } - } +struct GradientGpuBlockBuilder<'a> { + stops_range: ItemRange, + display_list: &'a BuiltDisplayList, } -impl Clone for GradientData { - fn clone(&self) -> GradientData { - GradientData { - colors_high: self.colors_high, - colors_low: self.colors_low, +impl<'a> GradientGpuBlockBuilder<'a> { + fn new(stops_range: ItemRange, + display_list: &'a BuiltDisplayList) -> GradientGpuBlockBuilder<'a> { + GradientGpuBlockBuilder { + stops_range: stops_range, + display_list: display_list, } } -} -impl GradientData { /// Generate a color ramp filling the indices in [start_idx, end_idx) and interpolating /// from start_color to end_color. - fn fill_colors(&mut self, start_idx: usize, end_idx: usize, start_color: &ColorF, end_color: &ColorF) { + fn fill_colors(&self, + start_idx: usize, + end_idx: usize, + start_color: &ColorF, + end_color: &ColorF, + entries: &mut [GradientDataEntry; GRADIENT_DATA_SIZE]) { // Calculate the color difference for individual steps in the ramp. let inv_steps = 1.0 / (end_idx - start_idx) as f32; let step_r = (end_color.r - start_color.r) * inv_steps; @@ -356,24 +332,16 @@ impl GradientData { let step_a = (end_color.a - start_color.a) * inv_steps; let mut cur_color = *start_color; - let mut cur_color_high = PackedTexel::high_bytes(&cur_color); - let mut cur_color_low = PackedTexel::low_bytes(&cur_color); // Walk the ramp writing start and end colors for each entry. for index in start_idx..end_idx { - let high_byte_entry = &mut self.colors_high[index]; - let low_byte_entry = &mut self.colors_low[index]; - - high_byte_entry.start_color = cur_color_high; - low_byte_entry.start_color = cur_color_low; + let entry = &mut entries[index]; + entry.start_color = cur_color; cur_color.r += step_r; cur_color.g += step_g; cur_color.b += step_b; cur_color.a += step_a; - cur_color_high = PackedTexel::high_bytes(&cur_color); - cur_color_low = PackedTexel::low_bytes(&cur_color); - high_byte_entry.end_color = cur_color_high; - low_byte_entry.end_color = cur_color_low; + entry.end_color = cur_color; } } @@ -387,7 +355,8 @@ impl GradientData { } // Build the gradient data from the supplied stops, reversing them if necessary. - fn build(&mut self, src_stops: AuxIter, reverse_stops: bool) { + fn build(&self, reverse_stops: bool, request: &mut GpuDataRequest) { + let src_stops = self.display_list.get(self.stops_range); // Preconditions (should be ensured by DisplayListBuilder): // * we have at least two stops @@ -399,9 +368,20 @@ impl GradientData { let mut cur_color = first.color.premultiplied(); debug_assert_eq!(first.offset, 0.0); + // A table of gradient entries, with two colors per entry, that specify the start and end color + // within the segment of the gradient space represented by that entry. To lookup a gradient result, + // first the entry index is calculated to determine which two colors to interpolate between, then + // the offset within that entry bucket is used to interpolate between the two colors in that entry. + // This layout preserves hard stops, as the end color for a given entry can differ from the start + // color for the following entry, despite them being adjacent. Colors are stored within in BGRA8 + // format for texture upload. This table requires the gradient color stops to be normalized to the + // range [0, 1]. The first and last entries hold the first and last color stop colors respectively, + // while the entries in between hold the interpolated color stop values for the range [0, 1]. + let mut entries: [GradientDataEntry; GRADIENT_DATA_SIZE] = unsafe { mem::uninitialized() }; + if reverse_stops { // Fill in the first entry (for reversed stops) with the first color stop - self.fill_colors(GRADIENT_DATA_LAST_STOP, GRADIENT_DATA_LAST_STOP + 1, &cur_color, &cur_color); + self.fill_colors(GRADIENT_DATA_LAST_STOP, GRADIENT_DATA_LAST_STOP + 1, &cur_color, &cur_color, &mut entries); // Fill in the center of the gradient table, generating a color ramp between each consecutive pair // of gradient stops. Each iteration of a loop will fill the indices in [next_idx, cur_idx). The @@ -413,7 +393,7 @@ impl GradientData { if next_idx < cur_idx { self.fill_colors(next_idx, cur_idx, - &next_color, &cur_color); + &next_color, &cur_color, &mut entries); cur_idx = next_idx; } @@ -422,10 +402,10 @@ impl GradientData { debug_assert_eq!(cur_idx, GRADIENT_DATA_TABLE_BEGIN); // Fill in the last entry (for reversed stops) with the last color stop - self.fill_colors(GRADIENT_DATA_FIRST_STOP, GRADIENT_DATA_FIRST_STOP + 1, &cur_color, &cur_color); + self.fill_colors(GRADIENT_DATA_FIRST_STOP, GRADIENT_DATA_FIRST_STOP + 1, &cur_color, &cur_color, &mut entries); } else { // Fill in the first entry with the first color stop - self.fill_colors(GRADIENT_DATA_FIRST_STOP, GRADIENT_DATA_FIRST_STOP + 1, &cur_color, &cur_color); + self.fill_colors(GRADIENT_DATA_FIRST_STOP, GRADIENT_DATA_FIRST_STOP + 1, &cur_color, &cur_color, &mut entries); // Fill in the center of the gradient table, generating a color ramp between each consecutive pair // of gradient stops. Each iteration of a loop will fill the indices in [cur_idx, next_idx). The @@ -437,7 +417,7 @@ impl GradientData { if next_idx > cur_idx { self.fill_colors(cur_idx, next_idx, - &cur_color, &next_color); + &cur_color, &next_color, &mut entries); cur_idx = next_idx; } @@ -446,11 +426,37 @@ impl GradientData { debug_assert_eq!(cur_idx, GRADIENT_DATA_TABLE_END); // Fill in the last entry with the last color stop - self.fill_colors(GRADIENT_DATA_LAST_STOP, GRADIENT_DATA_LAST_STOP + 1, &cur_color, &cur_color); + self.fill_colors(GRADIENT_DATA_LAST_STOP, GRADIENT_DATA_LAST_STOP + 1, &cur_color, &cur_color, &mut entries); + } + + for entry in entries.iter() { + request.push(entry.start_color.into()); + request.push(entry.end_color.into()); } } } +#[derive(Debug)] +pub struct RadialGradientPrimitiveCpu { + pub stops_range: ItemRange, + pub extend_mode: ExtendMode, + pub gpu_data_address: GpuStoreAddress, + pub gpu_data_count: i32, + pub gpu_blocks: [GpuBlockData; 3], +} + +impl RadialGradientPrimitiveCpu { + fn build_gpu_blocks_for_angle_radial(&self, + display_list: &BuiltDisplayList, + mut request: GpuDataRequest) { + request.extend_from_slice(&self.gpu_blocks); + + let gradient_builder = GradientGpuBlockBuilder::new(self.stops_range, + display_list); + gradient_builder.build(false, &mut request); + } +} + #[derive(Debug, Clone)] pub struct TextRunPrimitiveCpu { pub font_key: FontKey, @@ -647,7 +653,6 @@ pub struct PrimitiveStore { /// Gets uploaded directly to GPU via vertex texture. pub gpu_data32: VertexDataStore, - pub gpu_gradient_data: GradientDataStore, /// Resolved resource rects. pub gpu_resource_rects: VertexDataStore, @@ -671,7 +676,6 @@ impl PrimitiveStore { cpu_box_shadows: Vec::new(), prims_to_resolve: Vec::new(), gpu_data32: VertexDataStore::new(), - gpu_gradient_data: GradientDataStore::new(), gpu_resource_rects: VertexDataStore::new(), } } @@ -690,7 +694,6 @@ impl PrimitiveStore { cpu_box_shadows: recycle_vec(self.cpu_box_shadows), prims_to_resolve: recycle_vec(self.prims_to_resolve), gpu_data32: self.gpu_data32.recycle(), - gpu_gradient_data: self.gpu_gradient_data.recycle(), gpu_resource_rects: self.gpu_resource_rects.recycle(), } } @@ -807,12 +810,7 @@ impl PrimitiveStore { self.cpu_borders.push(border_cpu); metadata } - PrimitiveContainer::AlignedGradient(mut gradient_cpu) => { - let gpu_stops_address = self.gpu_data32.alloc(gradient_cpu.stops_count); - - gradient_cpu.gpu_data_address = gpu_stops_address; - gradient_cpu.gpu_data_count = gradient_cpu.stops_count as i32; - + PrimitiveContainer::AlignedGradient(gradient_cpu) => { let metadata = PrimitiveMetadata { // TODO: calculate if the gradient is actually opaque is_opaque: false, @@ -830,12 +828,7 @@ impl PrimitiveStore { self.cpu_gradients.push(gradient_cpu); metadata } - PrimitiveContainer::AngleGradient(mut gradient_cpu) => { - let gpu_gradient_address = self.gpu_gradient_data.alloc(1); - - gradient_cpu.gpu_data_address = gpu_gradient_address; - gradient_cpu.gpu_data_count = 1; - + PrimitiveContainer::AngleGradient(gradient_cpu) => { let metadata = PrimitiveMetadata { // TODO: calculate if the gradient is actually opaque is_opaque: false, @@ -853,12 +846,7 @@ impl PrimitiveStore { self.cpu_gradients.push(gradient_cpu); metadata } - PrimitiveContainer::RadialGradient(mut radial_gradient_cpu) => { - let gpu_gradient_address = self.gpu_gradient_data.alloc(1); - - radial_gradient_cpu.gpu_data_address = gpu_gradient_address; - radial_gradient_cpu.gpu_data_count = 1; - + PrimitiveContainer::RadialGradient(radial_gradient_cpu) => { let metadata = PrimitiveMetadata { // TODO: calculate if the gradient is actually opaque is_opaque: false, @@ -1258,46 +1246,9 @@ impl PrimitiveStore { // TODO(nical): Currently assuming no tile_spacing for yuv images. metadata.is_opaque = true; } - PrimitiveKind::AlignedGradient => { - let gradient = &mut self.cpu_gradients[metadata.cpu_prim_index.0]; - if gradient.cache_dirty { - let src_stops = display_list.get(gradient.stops_range); - - debug_assert!(gradient.gpu_data_count == src_stops.len() as i32); - let dest_stops = self.gpu_data32.get_slice_mut(gradient.gpu_data_address, - src_stops.len()); - - for (src, dest) in src_stops.zip(dest_stops.iter_mut()) { - *dest = GpuBlock32::from(GradientStopGpu { - offset: src.offset, - color: src.color.premultiplied(), - padding: [0.0; 3], - }); - } - - gradient.cache_dirty = false; - } - } - PrimitiveKind::AngleGradient => { - let gradient = &mut self.cpu_gradients[metadata.cpu_prim_index.0]; - if gradient.cache_dirty { - let src_stops = display_list.get(gradient.stops_range); - - let dest_gradient = self.gpu_gradient_data.get_mut(gradient.gpu_data_address); - dest_gradient.build(src_stops, gradient.reverse_stops); - gradient.cache_dirty = false; - } - } - PrimitiveKind::RadialGradient => { - let gradient = &mut self.cpu_radial_gradients[metadata.cpu_prim_index.0]; - if gradient.cache_dirty { - let src_stops = display_list.get(gradient.stops_range); - - let dest_gradient = self.gpu_gradient_data.get_mut(gradient.gpu_data_address); - dest_gradient.build(src_stops, false); - gradient.cache_dirty = false; - } - } + PrimitiveKind::AlignedGradient | + PrimitiveKind::AngleGradient | + PrimitiveKind::RadialGradient => {} } // Mark this GPU resource as required for this frame. @@ -1326,14 +1277,20 @@ impl PrimitiveStore { let yuv_image = &self.cpu_yuv_images[metadata.cpu_prim_index.0]; yuv_image.write_gpu_blocks(request); } - PrimitiveKind::AlignedGradient | + PrimitiveKind::AlignedGradient => { + let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0]; + gradient.build_gpu_blocks_for_aligned(display_list, + request); + } PrimitiveKind::AngleGradient => { let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0]; - gradient.write_gpu_blocks(request); + gradient.build_gpu_blocks_for_angle_radial(display_list, + request); } PrimitiveKind::RadialGradient => { let gradient = &self.cpu_radial_gradients[metadata.cpu_prim_index.0]; - gradient.write_gpu_blocks(request); + gradient.build_gpu_blocks_for_angle_radial(display_list, + request); } PrimitiveKind::TextRun => { let text = &self.cpu_text_runs[metadata.cpu_prim_index.0]; @@ -1376,7 +1333,7 @@ macro_rules! define_gpu_block { } define_gpu_block!(GpuBlock32: [f32; 8] = - GradientStopGpu, ClipCorner, ClipRect, ImageMaskData, + ClipCorner, ClipRect, ImageMaskData, BorderCornerClipData, BorderCornerDashClipData, BorderCornerDotClipData ); diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index f60a5d46c3..c90166e348 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -24,7 +24,6 @@ use internal_types::{CacheTextureId, RendererFrame, ResultMsg, TextureUpdateOp}; use internal_types::{TextureUpdateList, PackedVertex, RenderTargetMode}; use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, SourceTexture}; use internal_types::{BatchTextures, TextureSampler}; -use prim_store::GradientData; use profiler::{Profiler, BackendProfileCounters}; use profiler::{GpuProfileTag, RendererProfileTimers, RendererProfileCounters}; use record::ApiRecordingReceiver; @@ -341,25 +340,6 @@ impl GpuStoreLayout for VertexDataTextureLayout { type VertexDataTexture = GpuDataTexture; pub type VertexDataStore = GpuStore; -pub struct GradientDataTextureLayout; - -impl GpuStoreLayout for GradientDataTextureLayout { - fn image_format() -> ImageFormat { - ImageFormat::RGBA8 - } - - fn texture_width() -> usize { - mem::size_of::() / Self::texel_size() / 2 - } - - fn texture_filter() -> TextureFilter { - TextureFilter::Linear - } -} - -type GradientDataTexture = GpuDataTexture; -pub type GradientDataStore = GpuStore; - const TRANSFORM_FEATURE: &'static str = "TRANSFORM"; const SUBPIXEL_AA_FEATURE: &'static str = "SUBPIXEL_AA"; const CLIP_FEATURE: &'static str = "CLIP"; @@ -527,7 +507,6 @@ struct GpuDataTextures { render_task_texture: VertexDataTexture, data32_texture: VertexDataTexture, resource_rects_texture: VertexDataTexture, - gradient_data_texture: GradientDataTexture, } impl GpuDataTextures { @@ -537,7 +516,6 @@ impl GpuDataTextures { render_task_texture: VertexDataTexture::new(device), data32_texture: VertexDataTexture::new(device), resource_rects_texture: VertexDataTexture::new(device), - gradient_data_texture: GradientDataTexture::new(device), } } @@ -546,13 +524,11 @@ impl GpuDataTextures { self.resource_rects_texture.init(device, &mut frame.gpu_resource_rects); self.layer_texture.init(device, &mut frame.layer_texture_data); self.render_task_texture.init(device, &mut frame.render_task_data); - self.gradient_data_texture.init(device, &mut frame.gpu_gradient_data); device.bind_texture(TextureSampler::Layers, self.layer_texture.id); device.bind_texture(TextureSampler::RenderTasks, self.render_task_texture.id); device.bind_texture(TextureSampler::Data32, self.data32_texture.id); device.bind_texture(TextureSampler::ResourceRects, self.resource_rects_texture.id); - device.bind_texture(TextureSampler::Gradients, self.gradient_data_texture.id); } } diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index 9284b3c47c..12c802ad42 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -12,7 +12,7 @@ use internal_types::{ANGLE_FLOAT_TO_FIXED, BatchTextures, CacheTextureId, LowLev use internal_types::SourceTexture; use mask_cache::MaskCacheInfo; use prim_store::{CLIP_DATA_GPU_SIZE, DeferredResolve, GpuBlock32}; -use prim_store::{GradientData, PrimitiveCacheKey}; +use prim_store::PrimitiveCacheKey; use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore, TexelRect}; use profiler::FrameProfileCounters; use render_task::{AlphaRenderItem, MaskGeometryKind, MaskSegment, RenderTask, RenderTaskData}; @@ -530,23 +530,19 @@ impl AlphaRenderItem { let gradient_cpu = &ctx.prim_store.cpu_gradients[prim_metadata.cpu_prim_index.0]; let key = AlphaBatchKey::new(AlphaBatchKind::AlignedGradient, flags, blend_mode, textures); let batch = batch_list.get_suitable_batch(&key, item_bounding_rect); - for part_index in 0..(gradient_cpu.gpu_data_count - 1) { - batch.add_instance(base_instance.build(gradient_cpu.gpu_data_address.0 + part_index, 0)); + for part_index in 0..(gradient_cpu.stops_count - 1) { + batch.add_instance(base_instance.build(part_index as i32, 0)); } } PrimitiveKind::AngleGradient => { - let gradient_cpu = &ctx.prim_store.cpu_gradients[prim_metadata.cpu_prim_index.0]; let key = AlphaBatchKey::new(AlphaBatchKind::AngleGradient, flags, blend_mode, textures); let batch = batch_list.get_suitable_batch(&key, item_bounding_rect); - batch.add_instance(base_instance.build(gradient_cpu.gpu_data_address.0, - 0)); + batch.add_instance(base_instance.build(0, 0)); } PrimitiveKind::RadialGradient => { - let gradient_cpu = &ctx.prim_store.cpu_radial_gradients[prim_metadata.cpu_prim_index.0]; let key = AlphaBatchKey::new(AlphaBatchKind::RadialGradient, flags, blend_mode, textures); let batch = batch_list.get_suitable_batch(&key, item_bounding_rect); - batch.add_instance(base_instance.build(gradient_cpu.gpu_data_address.0, - 0)); + batch.add_instance(base_instance.build(0, 0)); } PrimitiveKind::YuvImage => { let image_yuv_cpu = &ctx.prim_store.cpu_yuv_images[prim_metadata.cpu_prim_index.0]; @@ -1638,7 +1634,6 @@ pub struct Frame { pub layer_texture_data: Vec, pub render_task_data: Vec, pub gpu_data32: Vec, - pub gpu_gradient_data: Vec, pub gpu_resource_rects: Vec, // List of updates that need to be pushed to the diff --git a/wrench/reftests/gradient/reftest.list b/wrench/reftests/gradient/reftest.list index eb83989105..3b3316ee8a 100644 --- a/wrench/reftests/gradient/reftest.list +++ b/wrench/reftests/gradient/reftest.list @@ -44,7 +44,7 @@ fuzzy(1,50) == tiling-linear-1.yaml tiling-linear-1-ref.yaml fuzzy(1,38) == tiling-linear-2.yaml tiling-linear-2-ref.yaml == tiling-linear-3.yaml tiling-linear-3-ref.yaml -fuzzy(1,16) == tiling-radial-1.yaml tiling-radial-1-ref.yaml +fuzzy(1,17) == tiling-radial-1.yaml tiling-radial-1-ref.yaml fuzzy(1,1) == tiling-radial-2.yaml tiling-radial-2-ref.yaml == tiling-radial-3.yaml tiling-radial-3-ref.yaml fuzzy(1,17) == tiling-radial-4.yaml tiling-radial-4-ref.yaml