From 0775efee0f46318598c7cec251098bfb9a01beb9 Mon Sep 17 00:00:00 2001 From: Doug Thayer Date: Mon, 6 Mar 2017 20:36:35 -0800 Subject: [PATCH 1/3] Add ordered dithering to gradient-like effects --- webrender/res/cs_blur.fs.glsl | 2 +- webrender/res/cs_box_shadow.fs.glsl | 2 +- webrender/res/prim_shared.glsl | 9 +++++ webrender/res/ps_angle_gradient.fs.glsl | 9 +++-- webrender/res/ps_angle_gradient.vs.glsl | 2 +- webrender/res/ps_box_shadow.fs.glsl | 2 +- webrender/res/ps_gradient.fs.glsl | 2 +- webrender/res/ps_radial_gradient.fs.glsl | 9 +++-- webrender/res/ps_radial_gradient.vs.glsl | 2 +- webrender/res/shared.glsl | 1 + webrender/src/device.rs | 8 ++++- webrender/src/gpu_store.rs | 11 +++++-- webrender/src/internal_types.rs | 13 +++++++- webrender/src/prim_store.rs | 27 ++++++++++----- webrender/src/renderer.rs | 42 +++++++++++++++++++++--- webrender/src/texture_cache.rs | 2 +- webrender_traits/src/image.rs | 2 ++ wrench/src/wrench.rs | 2 +- 18 files changed, 112 insertions(+), 35 deletions(-) diff --git a/webrender/res/cs_blur.fs.glsl b/webrender/res/cs_blur.fs.glsl index 64d6c368d6..19dcb15ca4 100644 --- a/webrender/res/cs_blur.fs.glsl +++ b/webrender/res/cs_blur.fs.glsl @@ -36,5 +36,5 @@ void main(void) { // Unpremultiply the alpha. color.rgb /= color.a; - oFragColor = color; + oFragColor = dither(color); } diff --git a/webrender/res/cs_box_shadow.fs.glsl b/webrender/res/cs_box_shadow.fs.glsl index 3243dc6d62..6fad1f1634 100644 --- a/webrender/res/cs_box_shadow.fs.glsl +++ b/webrender/res/cs_box_shadow.fs.glsl @@ -144,5 +144,5 @@ void main(void) { float value = color(pos, p0Rect, p1Rect, radii, sigma); value = max(value, 0.0); - oFragColor = vec4(1.0, 1.0, 1.0, vInverted == 1.0 ? 1.0 - value : value); + oFragColor = dither(vec4(1.0, 1.0, 1.0, vInverted == 1.0 ? 1.0 - value : value)); } diff --git a/webrender/res/prim_shared.glsl b/webrender/res/prim_shared.glsl index ff13f4efcd..9c9420c1cf 100644 --- a/webrender/res/prim_shared.glsl +++ b/webrender/res/prim_shared.glsl @@ -758,4 +758,13 @@ float do_clip() { return vClipMaskUvBounds.xy == vClipMaskUvBounds.zw ? 1.0: all(inside) ? textureLod(sCacheA8, vClipMaskUv, 0.0).r : 0.0; } + +vec4 dither(vec4 color) { + const int matrix_mask = 7; + + ivec2 pos = ivec2(gl_FragCoord) & ivec2(matrix_mask); + float noise_factor = 4.0 / 255.0; + float noise = texelFetch(sDither, pos, 0).r * noise_factor; + return color + vec4(noise, noise, noise, 0); +} #endif //WR_FRAGMENT_SHADER diff --git a/webrender/res/ps_angle_gradient.fs.glsl b/webrender/res/ps_angle_gradient.fs.glsl index 8cc7f1dac7..201fca6681 100644 --- a/webrender/res/ps_angle_gradient.fs.glsl +++ b/webrender/res/ps_angle_gradient.fs.glsl @@ -11,11 +11,10 @@ void main(void) { // gradient color entries (texture width / 2). float x = mix(clamp(vOffset, 0.0, 1.0), fract(vOffset), vGradientRepeat) * 0.5 * texture_size.x; - // Start at the center of first color in the nearest 2-color entry, then offset with the - // fractional remainder to interpolate between the colors. Rely on texture clamping when - // outside of valid range. x = 2.0 * floor(x) + 0.5 + fract(x); + float y = vGradientIndex + 1.0 / 256.0; - // Normalize the texture coordates so we can use texture() for bilinear filtering. - oFragColor = texture(sGradients, vec2(x, vGradientIndex) / texture_size); + // Use linear filtering to mix in the low bits (vGradientIndex + 1) with the high + // bits (vGradientIndex) + oFragColor = dither(texture(sGradients, vec2(x, y) / texture_size)); } diff --git a/webrender/res/ps_angle_gradient.vs.glsl b/webrender/res/ps_angle_gradient.vs.glsl index 0d47aaa56f..2f0b5ac344 100644 --- a/webrender/res/ps_angle_gradient.vs.glsl +++ b/webrender/res/ps_angle_gradient.vs.glsl @@ -27,7 +27,7 @@ void main(void) { vOffset = dot(vi.local_pos - start_point, dir) / dot(dir, dir); // V coordinate of gradient row in lookup texture. - vGradientIndex = float(prim.sub_index) + 0.5; + vGradientIndex = float(prim.sub_index) * 2.0 + 0.5; // Whether to repeat the gradient instead of clamping. vGradientRepeat = float(int(gradient.extend_mode.x) == EXTEND_MODE_REPEAT); diff --git a/webrender/res/ps_box_shadow.fs.glsl b/webrender/res/ps_box_shadow.fs.glsl index ef9e3c1cc8..aefbe00095 100644 --- a/webrender/res/ps_box_shadow.fs.glsl +++ b/webrender/res/ps_box_shadow.fs.glsl @@ -16,5 +16,5 @@ void main(void) { uv = mix(vCacheUvRectCoords.xy, vCacheUvRectCoords.zw, uv); // Modulate the box shadow by the color. - oFragColor = vColor * texture(sCacheRGBA8, vec3(uv, vUv.z)); + oFragColor = dither(vColor * texture(sCacheRGBA8, vec3(uv, vUv.z))); } diff --git a/webrender/res/ps_gradient.fs.glsl b/webrender/res/ps_gradient.fs.glsl index d2c705af49..4165f89b2c 100644 --- a/webrender/res/ps_gradient.fs.glsl +++ b/webrender/res/ps_gradient.fs.glsl @@ -12,5 +12,5 @@ void main(void) { #endif alpha = min(alpha, do_clip()); - oFragColor = vColor * vec4(1.0, 1.0, 1.0, alpha); + oFragColor = dither(vColor * vec4(1.0, 1.0, 1.0, alpha)); } diff --git a/webrender/res/ps_radial_gradient.fs.glsl b/webrender/res/ps_radial_gradient.fs.glsl index 1acd60df91..c5cdcd2e0f 100644 --- a/webrender/res/ps_radial_gradient.fs.glsl +++ b/webrender/res/ps_radial_gradient.fs.glsl @@ -50,11 +50,10 @@ void main(void) { // gradient color entries (texture width / 2). x = mix(clamp(x, 0.0, 1.0), fract(x), vGradientRepeat) * 0.5 * texture_size.x; - // Start at the center of first color in the nearest 2-color entry, then offset with the - // fractional remainder to interpolate between the colors. Rely on texture clamping when - // outside of valid range. x = 2.0 * floor(x) + 0.5 + fract(x); - // Normalize the texture coordates so we can use texture() for bilinear filtering. - oFragColor = texture(sGradients, vec2(x, vGradientIndex) / texture_size); + // Use linear filtering to mix in the low bits (vGradientIndex + 1) with the high + // bits (vGradientIndex) + float y = vGradientIndex + 1.0 / 256.0; + oFragColor = dither(texture(sGradients, vec2(x, y) / texture_size)); } diff --git a/webrender/res/ps_radial_gradient.vs.glsl b/webrender/res/ps_radial_gradient.vs.glsl index 86d951bf7b..781d82cb37 100644 --- a/webrender/res/ps_radial_gradient.vs.glsl +++ b/webrender/res/ps_radial_gradient.vs.glsl @@ -27,7 +27,7 @@ void main(void) { vEndRadius = gradient.start_end_radius_extend_mode.y; // V coordinate of gradient row in lookup texture. - vGradientIndex = float(prim.sub_index) + 0.5; + vGradientIndex = float(prim.sub_index) * 2.0 + 0.5; // Whether to repeat the gradient instead of clamping. vGradientRepeat = float(int(gradient.start_end_radius_extend_mode.z) == EXTEND_MODE_REPEAT); diff --git a/webrender/res/shared.glsl b/webrender/res/shared.glsl index f250a709c6..f0784f6c74 100644 --- a/webrender/res/shared.glsl +++ b/webrender/res/shared.glsl @@ -36,6 +36,7 @@ uniform sampler2D sColor0; uniform sampler2D sColor1; uniform sampler2D sColor2; +uniform sampler2D sDither; uniform sampler2D sMask; //====================================================================================== diff --git a/webrender/src/device.rs b/webrender/src/device.rs index bac7baf1f8..f89900b29b 100644 --- a/webrender/src/device.rs +++ b/webrender/src/device.rs @@ -1547,6 +1547,10 @@ impl Device { if u_color_2 != -1 { self.gl.uniform_1i(u_color_2, TextureSampler::Color2 as i32); } + let u_noise = self.gl.get_uniform_location(program.id, "sDither"); + if u_noise != -1 { + self.gl.uniform_1i(u_noise, TextureSampler::Dither as i32); + } let u_mask = self.gl.get_uniform_location(program.id, "sMask"); if u_mask != -1 { self.gl.uniform_1i(u_mask, TextureSampler::Mask as i32); @@ -1713,7 +1717,7 @@ impl Device { } ImageFormat::RGB8 => (gl::RGB, 3, data), ImageFormat::RGBA8 => (get_gl_format_bgra(self.gl()), 4, data), - ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(), + ImageFormat::Invalid | ImageFormat::RGBA16 | ImageFormat::RGBAF32 => unreachable!(), }; let row_length = match stride { @@ -2099,6 +2103,7 @@ fn gl_texture_formats_for_image_format(gl: &gl::Gl, format: ImageFormat) -> (gl: } } } + ImageFormat::RGBA16 => (gl::RGBA16UI as gl::GLint, gl::RGBA_INTEGER), ImageFormat::RGBAF32 => (gl::RGBA32F as gl::GLint, gl::RGBA), ImageFormat::Invalid => unreachable!(), } @@ -2107,6 +2112,7 @@ fn gl_texture_formats_for_image_format(gl: &gl::Gl, format: ImageFormat) -> (gl: fn gl_type_for_texture_format(format: ImageFormat) -> gl::GLuint { match format { ImageFormat::RGBAF32 => gl::FLOAT, + ImageFormat::RGBA16 => gl::UNSIGNED_SHORT, _ => gl::UNSIGNED_BYTE, } } diff --git a/webrender/src/gpu_store.rs b/webrender/src/gpu_store.rs index 68ba89c466..640324563d 100644 --- a/webrender/src/gpu_store.rs +++ b/webrender/src/gpu_store.rs @@ -30,6 +30,7 @@ pub trait GpuStoreLayout { fn texel_size() -> usize { match Self::image_format() { ImageFormat::RGBA8 => 4, + ImageFormat::RGBA16 => 8, ImageFormat::RGBAF32 => 16, _ => unreachable!(), } @@ -45,6 +46,10 @@ pub trait GpuStoreLayout { fn items_per_row() -> usize { Self::texture_width::() / Self::texels_per_item::() } + + fn rows_per_item() -> usize { + Self::texels_per_item::() / Self::texture_width::() + } } /// A CPU-side buffer storing content to be uploaded to the GPU. @@ -81,8 +86,10 @@ impl GpuStore { // Extend the data array to be a multiple of the row size. // This ensures memory safety when the array is passed to // OpenGL to upload to the GPU. - while items.len() % items_per_row != 0 { - items.push(T::default()); + if items_per_row != 0 { + while items_per_row != 0 && items.len() % items_per_row != 0 { + items.push(T::default()); + } } items diff --git a/webrender/src/internal_types.rs b/webrender/src/internal_types.rs index 9cd215e6d6..3548308628 100644 --- a/webrender/src/internal_types.rs +++ b/webrender/src/internal_types.rs @@ -170,6 +170,7 @@ impl GLContextWrapper { } 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; @@ -198,6 +199,7 @@ pub enum TextureSampler { Geometry, ResourceRects, Gradients, + Dither, } impl TextureSampler { @@ -313,7 +315,7 @@ pub struct PackedTexel { } impl PackedTexel { - pub fn from_color(color: &ColorF) -> PackedTexel { + pub fn high_bytes(color: &ColorF) -> PackedTexel { PackedTexel { b: (0.5 + color.b * COLOR_FLOAT_TO_FIXED).floor() as u8, g: (0.5 + color.g * COLOR_FLOAT_TO_FIXED).floor() as u8, @@ -321,6 +323,15 @@ impl PackedTexel { a: (0.5 + color.a * COLOR_FLOAT_TO_FIXED).floor() as u8, } } + + pub fn low_bytes(color: &ColorF) -> PackedTexel { + PackedTexel { + b: ((0.5 + color.b * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u16 & 0xff) as u8, + g: ((0.5 + color.g * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u16 & 0xff) as u8, + r: ((0.5 + color.r * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u16 & 0xff) as u8, + a: ((0.5 + color.a * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u16 & 0xff) as u8, + } + } } #[derive(Debug, Clone, Copy)] diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index e955a63fa4..40bb0a0265 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -277,16 +277,18 @@ pub struct GradientDataEntry { // 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 +// color for the following entry, despite them being adjacent. Colors are stored within in RGBA16 // format for texture upload. pub struct GradientData { - pub colors: [GradientDataEntry; GRADIENT_DATA_RESOLUTION], + pub colors_high: [GradientDataEntry; GRADIENT_DATA_RESOLUTION], + pub colors_low: [GradientDataEntry; GRADIENT_DATA_RESOLUTION], } impl Default for GradientData { fn default() -> GradientData { GradientData { - colors: unsafe { mem::uninitialized() } + colors_high: unsafe { mem::uninitialized() }, + colors_low: unsafe { mem::uninitialized() } } } } @@ -294,7 +296,8 @@ impl Default for GradientData { impl Clone for GradientData { fn clone(&self) -> GradientData { GradientData { - colors: self.colors, + colors_high: self.colors_high, + colors_low: self.colors_low, } } } @@ -314,18 +317,24 @@ impl GradientData { let step_a = (end_color.a - start_color.a) * inv_steps; let mut cur_color = *start_color; - let mut cur_packed_color = PackedTexel::from_color(&cur_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 entry in &mut self.colors[start_idx..end_idx] { - entry.start_color = cur_packed_color; + 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; cur_color.r += step_r; cur_color.g += step_g; cur_color.b += step_b; cur_color.a += step_a; - cur_packed_color = PackedTexel::from_color(&cur_color); - entry.end_color = cur_packed_color; + 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; } end_idx diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index e9b172360f..50903ee167 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -154,15 +154,22 @@ impl GpuDataTexture { } let items_per_row = L::items_per_row::(); + let rows_per_item = L::rows_per_item::(); // Extend the data array to be a multiple of the row size. // This ensures memory safety when the array is passed to // OpenGL to upload to the GPU. - while data.len() % items_per_row != 0 { - data.push(T::default()); + if items_per_row != 0 { + while data.len() % items_per_row != 0 { + data.push(T::default()); + } } - let height = data.len() / items_per_row; + let height = if items_per_row != 0 { + data.len() / items_per_row + } else { + data.len() * rows_per_item + }; device.init_texture(self.id, L::texture_width::() as u32, @@ -201,7 +208,7 @@ impl GpuStoreLayout for GradientDataTextureLayout { } fn texture_width() -> usize { - mem::size_of::() / Self::texel_size() + mem::size_of::() / Self::texel_size() / 2 } fn texture_filter() -> TextureFilter { @@ -513,6 +520,8 @@ pub struct Renderer { /// when no target is yet provided as a cache texture input. dummy_cache_texture_id: TextureId, + dither_matrix_texture_id: TextureId, + /// Optional trait object that allows the client /// application to provide external buffers for image data. external_image_handler: Option>, @@ -749,6 +758,18 @@ impl Renderer { 0xff, 0xff, 0xff, 0xff, ]; + + let dither_matrix: [u8; 64] = [ + 00, 48, 12, 60, 03, 51, 15, 63, + 32, 16, 44, 28, 35, 19, 47, 31, + 08, 56, 04, 52, 11, 59, 07, 55, + 40, 24, 36, 20, 43, 27, 39, 23, + 02, 50, 14, 62, 01, 49, 13, 61, + 34, 18, 46, 30, 33, 17, 45, 29, + 10, 58, 06, 54, 09, 57, 05, 53, + 42, 26, 38, 22, 41, 25, 37, 21 + ]; + // TODO: Ensure that the white texture can never get evicted when the cache supports LRU eviction! let white_image_id = texture_cache.new_item_id(); texture_cache.insert(white_image_id, @@ -773,6 +794,15 @@ impl Renderer { RenderTargetMode::LayerRenderTarget(1), None); + let dither_matrix_texture_id = device.create_texture_ids(1, TextureTarget::Default)[0]; + device.init_texture(dither_matrix_texture_id, + 8, + 8, + ImageFormat::A8, + TextureFilter::Nearest, + RenderTargetMode::None, + Some(&dither_matrix)); + let debug_renderer = DebugRenderer::new(&mut device); let gpu_data_textures = [ @@ -914,6 +944,7 @@ impl Renderer { main_thread_dispatcher: main_thread_dispatcher, cache_texture_id_map: Vec::new(), dummy_cache_texture_id: dummy_cache_texture_id, + dither_matrix_texture_id: dither_matrix_texture_id, external_image_handler: None, external_images: HashMap::with_hasher(Default::default()), vr_compositor_handler: vr_compositor, @@ -1254,6 +1285,9 @@ impl Renderer { self.device.bind_texture(TextureSampler::color(i), texture_id); } + // TODO: this probably isn't the best place for this. + self.device.bind_texture(TextureSampler::Dither, self.dither_matrix_texture_id); + self.device.update_vao_instances(vao, data, VertexUsageHint::Stream); self.device.draw_indexed_triangles_instanced_u16(6, data.len() as i32); self.profile_counters.vertices.add(6 * data.len()); diff --git a/webrender/src/texture_cache.rs b/webrender/src/texture_cache.rs index 20c6bb1c3d..fcc5fd86ad 100644 --- a/webrender/src/texture_cache.rs +++ b/webrender/src/texture_cache.rs @@ -607,7 +607,7 @@ impl TextureCache { ImageFormat::A8 => (&mut self.arena.pages_a8, &mut profile.pages_a8), ImageFormat::RGBA8 => (&mut self.arena.pages_rgba8, &mut profile.pages_rgba8), ImageFormat::RGB8 => (&mut self.arena.pages_rgb8, &mut profile.pages_rgb8), - ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(), + ImageFormat::Invalid | ImageFormat::RGBA16 | ImageFormat::RGBAF32 => unreachable!(), }; // TODO(gw): Handle this sensibly (support failing to render items that can't fit?) diff --git a/webrender_traits/src/image.rs b/webrender_traits/src/image.rs index 2cf49d970c..c02b684121 100644 --- a/webrender_traits/src/image.rs +++ b/webrender_traits/src/image.rs @@ -28,6 +28,7 @@ pub enum ImageFormat { RGB8 = 2, RGBA8 = 3, RGBAF32 = 4, + RGBA16 = 5, } impl ImageFormat { @@ -36,6 +37,7 @@ impl ImageFormat { ImageFormat::A8 => Some(1), ImageFormat::RGB8 => Some(3), ImageFormat::RGBA8 => Some(4), + ImageFormat::RGBA16 => Some(8), ImageFormat::RGBAF32 => Some(16), ImageFormat::Invalid => None, } diff --git a/wrench/src/wrench.rs b/wrench/src/wrench.rs index 044a4d8bd8..649c85d060 100644 --- a/wrench/src/wrench.rs +++ b/wrench/src/wrench.rs @@ -429,7 +429,7 @@ fn is_image_opaque(format: ImageFormat, bytes: &[u8]) -> bool { } ImageFormat::RGB8 => true, ImageFormat::A8 => false, - ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(), + ImageFormat::Invalid | ImageFormat::RGBA16 | ImageFormat::RGBAF32 => unreachable!(), } } From 1a20785ffc6da502d306af09f31758c60f0488a8 Mon Sep 17 00:00:00 2001 From: Doug Thayer Date: Wed, 8 Mar 2017 22:24:24 -0800 Subject: [PATCH 2/3] Add gradient perf test to wrench This will help assess whether dithering efforts have a meaningful performance tax or not. --- wrench/benchmarks/aligned-gradient.yaml | 62 +++++++++++++++++++++++ wrench/benchmarks/benchmarks.list | 2 + wrench/benchmarks/radial-gradient.yaml | 59 +++++++++++++++++++++ wrench/benchmarks/unaligned-gradient.yaml | 62 +++++++++++++++++++++++ 4 files changed, 185 insertions(+) create mode 100644 wrench/benchmarks/aligned-gradient.yaml create mode 100644 wrench/benchmarks/radial-gradient.yaml create mode 100644 wrench/benchmarks/unaligned-gradient.yaml diff --git a/wrench/benchmarks/aligned-gradient.yaml b/wrench/benchmarks/aligned-gradient.yaml new file mode 100644 index 0000000000..d91afc72e4 --- /dev/null +++ b/wrench/benchmarks/aligned-gradient.yaml @@ -0,0 +1,62 @@ +root: + items: + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 0, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 0, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 0, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 0, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 0, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 0, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 0, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 0, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 0, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 0, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false \ No newline at end of file diff --git a/wrench/benchmarks/benchmarks.list b/wrench/benchmarks/benchmarks.list index 0d30567037..c7508d1521 100644 --- a/wrench/benchmarks/benchmarks.list +++ b/wrench/benchmarks/benchmarks.list @@ -1,3 +1,5 @@ +aligned-gradient.yaml +unaligned-gradient.yaml simple-batching.yaml large-clip-rect.yaml transforms-simple.yaml diff --git a/wrench/benchmarks/radial-gradient.yaml b/wrench/benchmarks/radial-gradient.yaml new file mode 100644 index 0000000000..7ddc09e1e2 --- /dev/null +++ b/wrench/benchmarks/radial-gradient.yaml @@ -0,0 +1,59 @@ +--- +root: + items: + - type: radial-gradient + bounds: [ 0, 0, 1980, 1080] + start-center: [ 990, 540 ] + start-radius: 5 + end-center: [ 990, 540 ] + end-radius: 8000 + stops: [ 0.0, black, 1.0, white ] + repeat: false + - type: radial-gradient + bounds: [ 0, 0, 1980, 1080] + start-center: [ 990, 540 ] + start-radius: 5 + end-center: [ 990, 540 ] + end-radius: 8000 + stops: [ 0.0, black, 1.0, white ] + repeat: false + - type: radial-gradient + bounds: [ 0, 0, 1980, 1080] + start-center: [ 990, 540 ] + start-radius: 5 + end-center: [ 990, 540 ] + end-radius: 8000 + stops: [ 0.0, black, 1.0, white ] + repeat: false + - type: radial-gradient + bounds: [ 0, 0, 1980, 1080] + start-center: [ 990, 540 ] + start-radius: 5 + end-center: [ 990, 540 ] + end-radius: 8000 + stops: [ 0.0, black, 1.0, white ] + repeat: false + - type: radial-gradient + bounds: [ 0, 0, 1980, 1080] + start-center: [ 990, 540 ] + start-radius: 5 + end-center: [ 990, 540 ] + end-radius: 8000 + stops: [ 0.0, black, 1.0, white ] + repeat: false + - type: radial-gradient + bounds: [ 0, 0, 1980, 1080] + start-center: [ 990, 540 ] + start-radius: 5 + end-center: [ 990, 540 ] + end-radius: 8000 + stops: [ 0.0, black, 1.0, white ] + repeat: false + - type: radial-gradient + bounds: [ 0, 0, 1980, 1080] + start-center: [ 990, 540 ] + start-radius: 5 + end-center: [ 990, 540 ] + end-radius: 8000 + stops: [ 0.0, black, 1.0, white ] + repeat: false \ No newline at end of file diff --git a/wrench/benchmarks/unaligned-gradient.yaml b/wrench/benchmarks/unaligned-gradient.yaml new file mode 100644 index 0000000000..50cf8eba0f --- /dev/null +++ b/wrench/benchmarks/unaligned-gradient.yaml @@ -0,0 +1,62 @@ +root: + items: + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 1, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 1, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 1, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 1, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 1, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 1, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 1, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 1, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 1, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false + - type: gradient + bounds: [ 0, 0, 1980, 1080] + start: [ 0, -2000 ] + end: [ 1, 4000 ] + stops: [ 0.0, red, 1.0, green ] + repeat: false \ No newline at end of file From 6fa2881340f59685ae09b10761862c2068937202 Mon Sep 17 00:00:00 2001 From: Doug Thayer Date: Thu, 23 Mar 2017 10:36:50 -0700 Subject: [PATCH 3/3] Fixup commit for gradient banding work --- webrender/res/prim_shared.glsl | 2 +- webrender/res/ps_angle_gradient.fs.glsl | 2 +- webrender/res/ps_angle_gradient.vs.glsl | 2 +- webrender/res/ps_radial_gradient.fs.glsl | 2 +- webrender/res/ps_radial_gradient.vs.glsl | 2 +- webrender/src/device.rs | 4 +--- webrender/src/gpu_store.rs | 1 - webrender/src/internal_types.rs | 19 +++++++++---------- webrender/src/prim_store.rs | 2 +- webrender/src/texture_cache.rs | 2 +- webrender_traits/src/image.rs | 2 -- wrench/benchmarks/aligned-gradient.yaml | 2 +- wrench/benchmarks/radial-gradient.yaml | 2 +- wrench/benchmarks/unaligned-gradient.yaml | 2 +- wrench/src/wrench.rs | 2 +- 15 files changed, 21 insertions(+), 27 deletions(-) diff --git a/webrender/res/prim_shared.glsl b/webrender/res/prim_shared.glsl index 9c9420c1cf..2efa79868c 100644 --- a/webrender/res/prim_shared.glsl +++ b/webrender/res/prim_shared.glsl @@ -762,7 +762,7 @@ float do_clip() { vec4 dither(vec4 color) { const int matrix_mask = 7; - ivec2 pos = ivec2(gl_FragCoord) & ivec2(matrix_mask); + ivec2 pos = ivec2(gl_FragCoord.xy) & ivec2(matrix_mask); float noise_factor = 4.0 / 255.0; float noise = texelFetch(sDither, pos, 0).r * noise_factor; return color + vec4(noise, noise, noise, 0); diff --git a/webrender/res/ps_angle_gradient.fs.glsl b/webrender/res/ps_angle_gradient.fs.glsl index 201fca6681..7b6b773c28 100644 --- a/webrender/res/ps_angle_gradient.fs.glsl +++ b/webrender/res/ps_angle_gradient.fs.glsl @@ -12,9 +12,9 @@ void main(void) { float x = mix(clamp(vOffset, 0.0, 1.0), fract(vOffset), vGradientRepeat) * 0.5 * texture_size.x; x = 2.0 * floor(x) + 0.5 + fract(x); - float y = vGradientIndex + 1.0 / 256.0; // Use linear filtering to mix in the low bits (vGradientIndex + 1) with the high // bits (vGradientIndex) + float y = vGradientIndex * 2.0 + 0.5 + 1.0 / 256.0; oFragColor = dither(texture(sGradients, vec2(x, y) / texture_size)); } diff --git a/webrender/res/ps_angle_gradient.vs.glsl b/webrender/res/ps_angle_gradient.vs.glsl index 2f0b5ac344..366042a7ad 100644 --- a/webrender/res/ps_angle_gradient.vs.glsl +++ b/webrender/res/ps_angle_gradient.vs.glsl @@ -27,7 +27,7 @@ void main(void) { vOffset = dot(vi.local_pos - start_point, dir) / dot(dir, dir); // V coordinate of gradient row in lookup texture. - vGradientIndex = float(prim.sub_index) * 2.0 + 0.5; + vGradientIndex = float(prim.sub_index); // Whether to repeat the gradient instead of clamping. vGradientRepeat = float(int(gradient.extend_mode.x) == EXTEND_MODE_REPEAT); diff --git a/webrender/res/ps_radial_gradient.fs.glsl b/webrender/res/ps_radial_gradient.fs.glsl index c5cdcd2e0f..aaaa01ea3d 100644 --- a/webrender/res/ps_radial_gradient.fs.glsl +++ b/webrender/res/ps_radial_gradient.fs.glsl @@ -54,6 +54,6 @@ void main(void) { // Use linear filtering to mix in the low bits (vGradientIndex + 1) with the high // bits (vGradientIndex) - float y = vGradientIndex + 1.0 / 256.0; + float y = vGradientIndex * 2.0 + 0.5 + 1.0 / 256.0; oFragColor = dither(texture(sGradients, vec2(x, y) / texture_size)); } diff --git a/webrender/res/ps_radial_gradient.vs.glsl b/webrender/res/ps_radial_gradient.vs.glsl index 781d82cb37..6f929a95ac 100644 --- a/webrender/res/ps_radial_gradient.vs.glsl +++ b/webrender/res/ps_radial_gradient.vs.glsl @@ -27,7 +27,7 @@ void main(void) { vEndRadius = gradient.start_end_radius_extend_mode.y; // V coordinate of gradient row in lookup texture. - vGradientIndex = float(prim.sub_index) * 2.0 + 0.5; + vGradientIndex = float(prim.sub_index); // Whether to repeat the gradient instead of clamping. vGradientRepeat = float(int(gradient.start_end_radius_extend_mode.z) == EXTEND_MODE_REPEAT); diff --git a/webrender/src/device.rs b/webrender/src/device.rs index f89900b29b..f34b31f119 100644 --- a/webrender/src/device.rs +++ b/webrender/src/device.rs @@ -1717,7 +1717,7 @@ impl Device { } ImageFormat::RGB8 => (gl::RGB, 3, data), ImageFormat::RGBA8 => (get_gl_format_bgra(self.gl()), 4, data), - ImageFormat::Invalid | ImageFormat::RGBA16 | ImageFormat::RGBAF32 => unreachable!(), + ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(), }; let row_length = match stride { @@ -2103,7 +2103,6 @@ fn gl_texture_formats_for_image_format(gl: &gl::Gl, format: ImageFormat) -> (gl: } } } - ImageFormat::RGBA16 => (gl::RGBA16UI as gl::GLint, gl::RGBA_INTEGER), ImageFormat::RGBAF32 => (gl::RGBA32F as gl::GLint, gl::RGBA), ImageFormat::Invalid => unreachable!(), } @@ -2112,7 +2111,6 @@ fn gl_texture_formats_for_image_format(gl: &gl::Gl, format: ImageFormat) -> (gl: fn gl_type_for_texture_format(format: ImageFormat) -> gl::GLuint { match format { ImageFormat::RGBAF32 => gl::FLOAT, - ImageFormat::RGBA16 => gl::UNSIGNED_SHORT, _ => gl::UNSIGNED_BYTE, } } diff --git a/webrender/src/gpu_store.rs b/webrender/src/gpu_store.rs index 640324563d..9297d98baa 100644 --- a/webrender/src/gpu_store.rs +++ b/webrender/src/gpu_store.rs @@ -30,7 +30,6 @@ pub trait GpuStoreLayout { fn texel_size() -> usize { match Self::image_format() { ImageFormat::RGBA8 => 4, - ImageFormat::RGBA16 => 8, ImageFormat::RGBAF32 => 16, _ => unreachable!(), } diff --git a/webrender/src/internal_types.rs b/webrender/src/internal_types.rs index 3548308628..933d052561 100644 --- a/webrender/src/internal_types.rs +++ b/webrender/src/internal_types.rs @@ -316,20 +316,19 @@ pub struct PackedTexel { impl PackedTexel { pub fn high_bytes(color: &ColorF) -> PackedTexel { - PackedTexel { - b: (0.5 + color.b * COLOR_FLOAT_TO_FIXED).floor() as u8, - g: (0.5 + color.g * COLOR_FLOAT_TO_FIXED).floor() as u8, - r: (0.5 + color.r * COLOR_FLOAT_TO_FIXED).floor() as u8, - a: (0.5 + color.a * COLOR_FLOAT_TO_FIXED).floor() as u8, - } + Self::extract_bytes(color, COLOR_FLOAT_TO_FIXED) } pub fn low_bytes(color: &ColorF) -> PackedTexel { + Self::extract_bytes(color, COLOR_FLOAT_TO_FIXED_WIDE) + } + + fn extract_bytes(color: &ColorF, multiplier: f32) -> PackedTexel { PackedTexel { - b: ((0.5 + color.b * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u16 & 0xff) as u8, - g: ((0.5 + color.g * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u16 & 0xff) as u8, - r: ((0.5 + color.r * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u16 & 0xff) as u8, - a: ((0.5 + color.a * COLOR_FLOAT_TO_FIXED_WIDE).floor() as u16 & 0xff) as u8, + b: ((0.5 + color.b * multiplier).floor() as u32 & 0xff) as u8, + g: ((0.5 + color.g * multiplier).floor() as u32 & 0xff) as u8, + r: ((0.5 + color.r * multiplier).floor() as u32 & 0xff) as u8, + a: ((0.5 + color.a * multiplier).floor() as u32 & 0xff) as u8, } } } diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 40bb0a0265..380b56ee43 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -277,7 +277,7 @@ pub struct GradientDataEntry { // 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 RGBA16 +// color for the following entry, despite them being adjacent. Colors are stored within in BGRA8 // format for texture upload. pub struct GradientData { pub colors_high: [GradientDataEntry; GRADIENT_DATA_RESOLUTION], diff --git a/webrender/src/texture_cache.rs b/webrender/src/texture_cache.rs index fcc5fd86ad..20c6bb1c3d 100644 --- a/webrender/src/texture_cache.rs +++ b/webrender/src/texture_cache.rs @@ -607,7 +607,7 @@ impl TextureCache { ImageFormat::A8 => (&mut self.arena.pages_a8, &mut profile.pages_a8), ImageFormat::RGBA8 => (&mut self.arena.pages_rgba8, &mut profile.pages_rgba8), ImageFormat::RGB8 => (&mut self.arena.pages_rgb8, &mut profile.pages_rgb8), - ImageFormat::Invalid | ImageFormat::RGBA16 | ImageFormat::RGBAF32 => unreachable!(), + ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(), }; // TODO(gw): Handle this sensibly (support failing to render items that can't fit?) diff --git a/webrender_traits/src/image.rs b/webrender_traits/src/image.rs index c02b684121..2cf49d970c 100644 --- a/webrender_traits/src/image.rs +++ b/webrender_traits/src/image.rs @@ -28,7 +28,6 @@ pub enum ImageFormat { RGB8 = 2, RGBA8 = 3, RGBAF32 = 4, - RGBA16 = 5, } impl ImageFormat { @@ -37,7 +36,6 @@ impl ImageFormat { ImageFormat::A8 => Some(1), ImageFormat::RGB8 => Some(3), ImageFormat::RGBA8 => Some(4), - ImageFormat::RGBA16 => Some(8), ImageFormat::RGBAF32 => Some(16), ImageFormat::Invalid => None, } diff --git a/wrench/benchmarks/aligned-gradient.yaml b/wrench/benchmarks/aligned-gradient.yaml index d91afc72e4..b0e2f0a645 100644 --- a/wrench/benchmarks/aligned-gradient.yaml +++ b/wrench/benchmarks/aligned-gradient.yaml @@ -59,4 +59,4 @@ root: start: [ 0, -2000 ] end: [ 0, 4000 ] stops: [ 0.0, red, 1.0, green ] - repeat: false \ No newline at end of file + repeat: false diff --git a/wrench/benchmarks/radial-gradient.yaml b/wrench/benchmarks/radial-gradient.yaml index 7ddc09e1e2..375485ed68 100644 --- a/wrench/benchmarks/radial-gradient.yaml +++ b/wrench/benchmarks/radial-gradient.yaml @@ -56,4 +56,4 @@ root: end-center: [ 990, 540 ] end-radius: 8000 stops: [ 0.0, black, 1.0, white ] - repeat: false \ No newline at end of file + repeat: false diff --git a/wrench/benchmarks/unaligned-gradient.yaml b/wrench/benchmarks/unaligned-gradient.yaml index 50cf8eba0f..ea7738202d 100644 --- a/wrench/benchmarks/unaligned-gradient.yaml +++ b/wrench/benchmarks/unaligned-gradient.yaml @@ -59,4 +59,4 @@ root: start: [ 0, -2000 ] end: [ 1, 4000 ] stops: [ 0.0, red, 1.0, green ] - repeat: false \ No newline at end of file + repeat: false diff --git a/wrench/src/wrench.rs b/wrench/src/wrench.rs index 649c85d060..044a4d8bd8 100644 --- a/wrench/src/wrench.rs +++ b/wrench/src/wrench.rs @@ -429,7 +429,7 @@ fn is_image_opaque(format: ImageFormat, bytes: &[u8]) -> bool { } ImageFormat::RGB8 => true, ImageFormat::A8 => false, - ImageFormat::Invalid | ImageFormat::RGBA16 | ImageFormat::RGBAF32 => unreachable!(), + ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(), } }