Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added ordered dithering to gradient-like effects #966

Merged
merged 3 commits into from
Mar 24, 2017

Conversation

squarewave
Copy link
Contributor

@squarewave squarewave commented Mar 7, 2017

Closes #929

It's a bit rough around the edges, so any criticism is completely welcome - just hoping to help out!


This change is Reviewable

@glennw
Copy link
Member

glennw commented Mar 7, 2017

Thanks for looking into this issue! I'm a bit concerned about the extra shader costs of the approach, since it seems to introduce quite a few more instructions and also an extra texture fetch (although that should be in cache almost all the time).

We're not currently using sRGB or any of the usual techniques to reduce banding. It seems like that may be a better approach to fixing this - thoughts @squarewave and @kvark ?

I'm hoping to land some benchmark / profiling support in wrench in the next couple of days, which would allow us to quantify if this has any noticeable impact on framerates.

@squarewave
Copy link
Contributor Author

While I'm on board with using sRGB, I'm not familiar with how it would reduce this kind of banding. At a certain point a monitor can only represent so many steps between two colors regardless of color space, and they'll be far enough apart from each other that the human eye will pick up on it. Dithering is the only way I know of to compensate for this, but I'm by no means an expert.

Quantifying would be great! I definitely felt uncertain while writing this what kind of impact it would have. However, I do know that Chrome is currently using an ordered dither on Windows for this purpose. (Tested by just screen-shotting a gentle gradient in Chrome and zooming in.)

Copy link
Member

@kvark kvark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@glennw good point about sRGB!
A gradient is linearly interpolated, so we'll need to convert it to sRGB space in order for the linearity to show properly on the screen. Currently we don't touch GL_FRAMEBUFFER_SRGB, and it's false by default. I think Gecko folks would want to use a real gamma conversion table (instead of GL's built-in), so we'd need this mode supported as well. (Which, btw, may be conveniently combined with the post-fx pass of #957). cc @nical @jrmuizel

As for this PR, I think it's good to go. There is a few nits spotted, but I'm not too worried about the implications of adding it:

  • complexity wise, having the dither ability is going to be handy anyway
  • performance wise, it only affects the blur, box shadows, and dither shaders


vec4 dither(vec4 color) {
const float matrix_size = 8;
// TODO: should we mask it here or set the texture's wrapping to GL_REPEAT?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need a texture sample at all. We could just texelFetch instead

// TODO: should we mask it here or set the texture's wrapping to GL_REPEAT?
const int matrix_mask = 7;

vec2 pos = vec2(int(gl_FragCoord.x) & matrix_mask, int(gl_FragCoord.y) & matrix_mask);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could just do ivec2(gl_FragCoord.xy) & ivec2(matrix_mask)

@squarewave
Copy link
Contributor Author

One thing that remains, which I just finished diagnosing. For angle and radial gradients, we pre-build a texture for the gradient like so:

prim_store.rs:316:

fn fill_colors(&mut self, start_idx: usize, end_idx: usize, start_color: &ColorF, end_color: &ColorF) -> usize {
    if start_idx >= end_idx {
        return start_idx;
    }

    // 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;
    let step_g = (end_color.g - start_color.g) * inv_steps;
    let step_b = (end_color.b - start_color.b) * inv_steps;
    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);

    // 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;

        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;
    }

    end_idx
}

Filling the texture out with this data causes it to be prematurely quantized, meaning our dithering doesn't really do too much. I feel like there's a number of ways we could tackle this, but I just wanted to see if anything was already in the works to use a different mechanism for angle and radial gradients.

@kvark
Copy link
Member

kvark commented Mar 8, 2017

@squarewave Nicely spotted!
We could use a higher-bpp texture for those gradients.

Alternatively, we could provide 2 textures: one carrying just the segment index, and another actually providing the segment data. The pixel shader would then read the relevant segment and interpolate with code between the start/end colors.

@glennw
Copy link
Member

glennw commented Mar 9, 2017

@squarewave I added a benchmark module here - #969.

Perhaps we could add a couple of gradient related benchmarks? Maybe a full screen linear gradient and a full screen angle gradient?

@squarewave
Copy link
Contributor Author

@kvark - good ideas! I went with increasing the bpp for now since it's much simpler to do, but I do wonder if this solution is viable on Android and other architectures which I'm not very set up to test. Thoughts?

Also, here are some results of the benchmarks (seems to be an impact - not sure how to assess how major it is)

Before:

[
    {
      "name": "benchmarks\\gradients.yaml",
      "composite_time_ns": 460775,
      "paint_time_ns": 308330,
      "draw_calls": 3
    },
    {
      "name": "benchmarks\\gradients.yaml",
      "composite_time_ns": 542940,
      "paint_time_ns": 307200,
      "draw_calls": 3
    },
    {
      "name": "benchmarks\\gradients.yaml",
      "composite_time_ns": 446595,
      "paint_time_ns": 307322,
      "draw_calls": 3
    },
]

After:

[
    {
      "name": "benchmarks\\gradients.yaml",
      "composite_time_ns": 589848,
      "paint_time_ns": 435536,
      "draw_calls": 3
    },
    {
      "name": "benchmarks\\gradients.yaml",
      "composite_time_ns": 590947,
      "paint_time_ns": 435269,
      "draw_calls": 3
    },
    {
      "name": "benchmarks\\gradients.yaml",
      "composite_time_ns": 588059,
      "paint_time_ns": 435696,
      "draw_calls": 3
    },
]

@kvark
Copy link
Member

kvark commented Mar 9, 2017

@squarewave I don't think RGBA32F is the best choice here. We should use unsigned normalized RGBA16 instead. If it's not supported yet, we need to add it. That would retain the high quality and make it a tad faster.

@squarewave
Copy link
Contributor Author

Done. Also, I split out the performance benchmarks for the two cases.

Before (no dithering - BGRA8 texture):

{
  "tests": [
    {
      "name": "benchmarks\\aligned-gradient.yaml",
      "composite_time_ns": 704614,
      "paint_time_ns": 1049088,
      "draw_calls": 2
    },
    {
      "name": "benchmarks\\unaligned-gradient.yaml",
      "composite_time_ns": 975543,
      "paint_time_ns": 988997,
      "draw_calls": 2
    },
    {
      "name": "benchmarks\\simple-batching.yaml",
      "composite_time_ns": 308162,
      "paint_time_ns": 406149,
      "draw_calls": 1
    },
    {
      "name": "benchmarks\\large-clip-rect.yaml",
      "composite_time_ns": 1028642,
      "paint_time_ns": 618181,
      "draw_calls": 10
    }
  ]
}

After (dithering - RGBA16 texture):

{
  "tests": [
    {
      "name": "benchmarks\\aligned-gradient.yaml",
      "composite_time_ns": 732871,
      "paint_time_ns": 1239525,
      "draw_calls": 2
    },
    {
      "name": "benchmarks\\unaligned-gradient.yaml",
      "composite_time_ns": 1453478,
      "paint_time_ns": 1243402,
      "draw_calls": 2
    },
    {
      "name": "benchmarks\\simple-batching.yaml",
      "composite_time_ns": 501355,
      "paint_time_ns": 500986,
      "draw_calls": 1
    },
    {
      "name": "benchmarks\\large-clip-rect.yaml",
      "composite_time_ns": 999048,
      "paint_time_ns": 617669,
      "draw_calls": 10
    }
  ]
}

@squarewave
Copy link
Contributor Author

(One last note, the benchmarks are fairly noisy - I don't know if that's just my machine or if it's just the nature of the domain. Just thought I'd mention it.)

@kvark
Copy link
Member

kvark commented Mar 10, 2017

Code looks great!
My last question/request would be to check how compatible is RGBA16 with Android/ARM.

@squarewave
Copy link
Contributor Author

From what I can tell it's not supported: http://docs.gl/es3/glTexImage2D

Should I just fall back to RGBA8 on these?

@bors-servo
Copy link
Contributor

☔ The latest upstream changes (presumably #965) made this pull request unmergeable. Please resolve the merge conflicts.

@kvark
Copy link
Member

kvark commented Mar 14, 2017

@squarewave it doesn't support the normalized version, but there is RGBA16UI. I think we should just convert the code to use the non-normalized format and ship it on all platforms.

@squarewave
Copy link
Contributor Author

squarewave commented Mar 15, 2017

So, unfortunately linear texture filtering doesn't seem to work on non-normalized integer formats. The only mention I could find on this was this thread, but I confirmed it by simply increasing GRADIENT_DATA_RESOLUTION until the banding I was seeing went away.

We could manually interpolate in the shader, but I don't have a good intuition as far as how performant that would be. Might be time to go to the dual-texture approach. Thoughts?

@kvark
Copy link
Member

kvark commented Mar 15, 2017

@squarewave argh, you are right. I forgot that you need interpolation...
Given that you are only sampling across the line, I'd vote for doing the bilinear sampling manually - only 2 texel fetches are required.

@squarewave squarewave force-pushed the master branch 2 times, most recently from 5948ae4 to 19aa850 Compare March 15, 2017 18:28
@glennw
Copy link
Member

glennw commented Mar 15, 2017

@squarewave Thanks for the update! Are you able to run this against the Servo WPT/CSS test suite locally to make sure there's no regressions there? If that's difficult / not possible - just let me know and I'll pull this branch locally sometime today and run the test suite here.

@squarewave
Copy link
Contributor Author

@glennw barring unexpected things I should be able to do that tonight :)

@bors-servo
Copy link
Contributor

☔ The latest upstream changes (presumably #984) made this pull request unmergeable. Please resolve the merge conflicts.

@squarewave
Copy link
Contributor Author

Running 10198 tests in web-platform-tests

  ▶ FAIL [expected PASS] /css-flexbox-1_dev/html/align-content-002.htm
  └   → /css-flexbox-1_dev/html/align-content-002.htm 9818ef82bee899fb74e6a57a7bb842ff0ae10208
/css-flexbox-1_dev/html/reference/align-content-001-ref.htm 7c6e309cde779542674789ef9fe6d190fc1be55f
Testing 9818ef82bee899fb74e6a57a7bb842ff0ae10208 == 7c6e309cde779542674789ef9fe6d190fc1be55f

  ▶ FAIL [expected PASS] /css-flexbox-1_dev/html/align-content-001.htm
  └   → /css-flexbox-1_dev/html/align-content-001.htm 133dd1c269bbe9b3fbc675b560e3ad8b88546bc5
/css-flexbox-1_dev/html/reference/align-content-001-ref.htm 7c6e309cde779542674789ef9fe6d190fc1be55f
Testing 133dd1c269bbe9b3fbc675b560e3ad8b88546bc5 == 7c6e309cde779542674789ef9fe6d190fc1be55f

  ▶ FAIL [expected PASS] /css-flexbox-1_dev/html/align-content-003.htm
  └   → /css-flexbox-1_dev/html/align-content-003.htm 81ca89d8923b1122f01d6b2dbbbf5bb08993cdcf
/css-flexbox-1_dev/html/reference/align-content-001-ref.htm 7c6e309cde779542674789ef9fe6d190fc1be55f
Testing 81ca89d8923b1122f01d6b2dbbbf5bb08993cdcf == 7c6e309cde779542674789ef9fe6d190fc1be55f

  ▶ FAIL [expected PASS] /css-flexbox-1_dev/html/align-content-005.htm
  └   → /css-flexbox-1_dev/html/align-content-005.htm 2cc0ed7fa06b704973b43122150c86e385427c06
/css-flexbox-1_dev/html/reference/align-content-001-ref.htm 7c6e309cde779542674789ef9fe6d190fc1be55f
Testing 2cc0ed7fa06b704973b43122150c86e385427c06 == 7c6e309cde779542674789ef9fe6d190fc1be55f

  ▶ FAIL [expected PASS] /css-flexbox-1_dev/html/align-items-001.htm
  └   → /css-flexbox-1_dev/html/align-items-001.htm 133dd1c269bbe9b3fbc675b560e3ad8b88546bc5
/css-flexbox-1_dev/html/reference/align-content-001-ref.htm 7c6e309cde779542674789ef9fe6d190fc1be55f
Testing 133dd1c269bbe9b3fbc675b560e3ad8b88546bc5 == 7c6e309cde779542674789ef9fe6d190fc1be55f

  ▶ FAIL [expected PASS] /css-flexbox-1_dev/html/align-items-002.htm
  └   → /css-flexbox-1_dev/html/align-items-002.htm 8eca5b9fafb2acb1f0fcfb1cafcc6be8ea025bd5
/css-flexbox-1_dev/html/reference/align-content-001-ref.htm 7c6e309cde779542674789ef9fe6d190fc1be55f
Testing 8eca5b9fafb2acb1f0fcfb1cafcc6be8ea025bd5 == 7c6e309cde779542674789ef9fe6d190fc1be55f

  ▶ FAIL [expected PASS] /css-flexbox-1_dev/html/align-items-003.htm
  └   → /css-flexbox-1_dev/html/align-items-003.htm 444b56cfbd74ca2a5a0df8318babcf43aa74f0cc
/css-flexbox-1_dev/html/reference/align-content-001-ref.htm 7c6e309cde779542674789ef9fe6d190fc1be55f
Testing 444b56cfbd74ca2a5a0df8318babcf43aa74f0cc == 7c6e309cde779542674789ef9fe6d190fc1be55f

  ▶ FAIL [expected PASS] /css-flexbox-1_dev/html/justify-content-002.htm
  └   → /css-flexbox-1_dev/html/justify-content-002.htm 4b0df58a95c521d09ee24049631c0d11b1a8c01a
/css-flexbox-1_dev/html/reference/justify-content-001-ref.htm 3b852bd0fc8fa488cfe9957717f283b5fead2032
Testing 4b0df58a95c521d09ee24049631c0d11b1a8c01a == 3b852bd0fc8fa488cfe9957717f283b5fead2032

  ▶ FAIL [expected PASS] /css-flexbox-1_dev/html/justify-content-001.htm
  └   → /css-flexbox-1_dev/html/justify-content-001.htm fa3193dbe0b5475b5ea6bd3d90e1cba0d7b4c1e5
/css-flexbox-1_dev/html/reference/justify-content-001-ref.htm 3b852bd0fc8fa488cfe9957717f283b5fead2032
Testing fa3193dbe0b5475b5ea6bd3d90e1cba0d7b4c1e5 == 3b852bd0fc8fa488cfe9957717f283b5fead2032

  ▶ FAIL [expected PASS] /css-flexbox-1_dev/html/justify-content-003.htm
  └   → /css-flexbox-1_dev/html/justify-content-003.htm bb865eed4fa2cdbef017bb610d1a92d1934b6d9e
/css-flexbox-1_dev/html/reference/justify-content-001-ref.htm 3b852bd0fc8fa488cfe9957717f283b5fead2032
Testing bb865eed4fa2cdbef017bb610d1a92d1934b6d9e == 3b852bd0fc8fa488cfe9957717f283b5fead2032

  ▶ FAIL [expected PASS] /css-flexbox-1_dev/html/justify-content-005.htm
  └   → /css-flexbox-1_dev/html/justify-content-005.htm 3d5be9f646977988b300f2f9c6a987c427a0c910
/css-flexbox-1_dev/html/reference/justify-content-001-ref.htm 3b852bd0fc8fa488cfe9957717f283b5fead2032
Testing 3d5be9f646977988b300f2f9c6a987c427a0c910 == 3b852bd0fc8fa488cfe9957717f283b5fead2032

  ▶ FAIL [expected PASS] /css-flexbox-1_dev/html/justify-content-004.htm
  └   → /css-flexbox-1_dev/html/justify-content-004.htm 3a2465c5af64e71912461976a2aefad803089789
/css-flexbox-1_dev/html/reference/justify-content-001-ref.htm 3b852bd0fc8fa488cfe9957717f283b5fead2032
Testing 3a2465c5af64e71912461976a2aefad803089789 == 3b852bd0fc8fa488cfe9957717f283b5fead2032

  ▶ TIMEOUT [expected PASS] /css-text-decor-3_dev/html/text-emphasis-style-property-010Cn.htm
  │
  │ VMware, Inc.
  │ Gallium 0.4 on softpipe
  │ 3.3 (Core Profile) Mesa 12.0.1
  │ assertion failed: glyphs[0] != 0 (thread LayoutThread PipelineId { namespace_id: PipelineNamespaceId(0), index: PipelineIndex(1) }, at /Users/dthayer/servo/components/gfx/platform/macos/font.rs:263)
  │ stack backtrace:
  │    0:        0x103f32bbe - backtrace::backtrace::trace::hef11bbe02813de13
  │    1:        0x103f3330c - backtrace::capture::Backtrace::new::hb5a725a088a2a2fc
  │    2:        0x1039a0290 - servo::main::_$u7b$$u7b$closure$u7d$$u7d$::h45fbb6788f29b505
  │    3:        0x10542ea19 - std::panicking::rust_panic_with_hook::hdbc3bba6a9dc0bb9
  │    4:        0x10506fc14 - std::panicking::begin_panic::hd2bb277bad3d64da
  │    5:        0x10508dbf7 - _$LT$gfx..platform..macos..font..FontHandle$u20$as$u20$gfx..font..FontHandleMethods$GT$::glyph_index::hca970d886a79541d
  │    6:        0x104fa1047 - _$LT$core..slice..Iter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..iter..iterator..Iterator$GT$::position::_$u7b$$u7b$closure$u7d$$u7d$::h28a960e6f23c750e
  │    7:        0x104ffb091 - layout::text::TextRunScanner::scan_for_runs::h2a3c4a4f6bfa50bf
  │    8:        0x103f992a8 - _$LT$layout..construct..FlowConstructor$LT$$u27$a$C$$u20$ConcreteThreadSafeLayoutNode$GT$$GT$::build_flow_for_block_starting_with_fragments::he2171bd51e03f256
  │    9:        0x103f9787b - _$LT$layout..construct..FlowConstructor$LT$$u27$a$C$$u20$ConcreteThreadSafeLayoutNode$GT$$GT$::build_flow_for_block_like::hc80bc7799fd5ad07
  │   10:        0x103f96dd2 - _$LT$layout..construct..FlowConstructor$LT$$u27$a$C$$u20$ConcreteThreadSafeLayoutNode$GT$$GT$::build_flow_for_block::hcdda499a98c62106
  │   11:        0x103f494ca - _$LT$layout..construct..FlowConstructor$LT$$u27$a$C$$u20$ConcreteThreadSafeLayoutNode$GT$$u20$as$u20$layout..traversal..PostorderNodeMutTraversal$LT$ConcreteThreadSafeLayoutNode$GT$$GT$::process::h89407a27e3122a63
  │   12:        0x103f39494 - _$LT$layout..traversal..RecalcStyleAndConstructFlows$u20$as$u20$style..traversal..DomTraversal$LT$E$GT$$GT$::process_postorder::h82f6a02624e5bfd5
  │   13:        0x103f75be3 - style::sequential::traverse_dom::doit::hc564a9203372da68
  │   14:        0x103f75bc3 - style::sequential::traverse_dom::doit::hc564a9203372da68
  │   15:        0x103f75bc3 - style::sequential::traverse_dom::doit::hc564a9203372da68
  │   16:        0x103faf47b - layout_thread::LayoutThread::handle_reflow::hcf6f8a39747152f9
  │   17:        0x103fa9176 - layout_thread::LayoutThread::handle_request_helper::h747ea78e6fbe9281
  │   18:        0x103fa5225 - _$LT$layout_thread..LayoutThread$u20$as$u20$layout_traits..LayoutThreadFactory$GT$::create::_$u7b$$u7b$closure$u7d$$u7d$::h01f75976a8c77f20
  │   19:        0x103f5b067 - std::panicking::try::do_call::h9c41fad03aec50d6
  │   20:        0x10542f94a - __rust_maybe_catch_panic
  │   21:        0x103f711d8 - _$LT$F$u20$as$u20$alloc..boxed..FnBox$LT$A$GT$$GT$::call_box::h5f4a61ddc668412a
  │   22:        0x10542b5a4 - std::sys::imp::thread::Thread::new::thread_start::h4008e1859fbd98b8
  │   23:     0x7fffb5484aaa - _pthread_body
  │   24:     0x7fffb54849f6 - _pthread_start
  │ ERROR:servo: assertion failed: glyphs[0] != 0
  │ called `Result::unwrap()` on an `Err` value: "PoisonError { inner: .. }" (thread ScriptThread PipelineId { namespace_id: PipelineNamespaceId(0), index: PipelineIndex(1) }, at src/libcore/result.rs:860)
  │ stack backtrace:
  │    0:        0x103f32bbe - backtrace::backtrace::trace::hef11bbe02813de13
  │    1:        0x103f3330c - backtrace::capture::Backtrace::new::hb5a725a088a2a2fc
  │    2:        0x1039a0290 - servo::main::_$u7b$$u7b$closure$u7d$$u7d$::h45fbb6788f29b505
  │    3:        0x10542ea19 - std::panicking::rust_panic_with_hook::hdbc3bba6a9dc0bb9
  │    4:        0x10542e874 - std::panicking::begin_panic::ha249c774b9bf96e1
  │    5:        0x10542e7e2 - std::panicking::begin_panic_fmt::ha197daaf02a649ab
  │    6:        0x10542e747 - rust_begin_unwind
  │    7:        0x105456bd0 - core::panicking::panic_fmt::h7414cb5ce71ea361
  │    8:        0x104f8d368 - core::result::unwrap_failed::h3026420b57abaf09
  │    9:        0x104fe931b - _$LT$layout..query..LayoutRPCImpl$u20$as$u20$script_layout_interface..rpc..LayoutRPC$GT$::pending_images::h0bfc01154ca41770
  │   10:        0x104487e2d - script::dom::window::Window::force_reflow::hee782c4e5d3cfebe
  │   11:        0x10448ac0b - script::dom::window::Window::reflow::had2e67c414225403
  │   12:        0x104336040 - script::dom::document::Document::finish_load::had0582113ce1d160
  │   13:        0x104431092 - script::dom::servoparser::ServoParser::do_parse_sync::h11f453f0800f36a9
  │   14:        0x104430bd6 - script::dom::servoparser::ServoParser::parse_sync::h5039fa5f462fecae
  │   15:        0x104438daf - _$LT$script..dom..servoparser..ParserContext$u20$as$u20$net_traits..FetchResponseListener$GT$::process_response_eof::h5af91aa95996bb71
  │   16:        0x1044b01b8 - _$LT$script..network_listener..ListenerRunnable$LT$A$C$$u20$Listener$GT$$u20$as$u20$script..script_thread..Runnable$GT$::handler::h6d17770caa6c013d
  │   17:        0x1044cf0c4 - script::script_thread::ScriptThread::handle_msg_from_script::h8c3244c75be2f0bb
  │   18:        0x1044c9a61 - script::script_thread::ScriptThread::handle_msgs::_$u7b$$u7b$closure$u7d$$u7d$::h249c5261d18e8760
  │   19:        0x1044c566a - script::script_thread::ScriptThread::handle_msgs::h315521521da5463b
  │   20:        0x1041141a7 - std::panicking::try::do_call::hac5d73e70ab1f3ab
  │   21:        0x10542f94a - __rust_maybe_catch_panic
  │   22:        0x1041e91aa - _$LT$F$u20$as$u20$alloc..boxed..FnBox$LT$A$GT$$GT$::call_box::hfef57d36b2ba8ce3
  │   23:        0x10542b5a4 - std::sys::imp::thread::Thread::new::thread_start::h4008e1859fbd98b8
  │   24:     0x7fffb5484aaa - _pthread_body
  │   25:     0x7fffb54849f6 - _pthread_start
  └ ERROR:servo: called `Result::unwrap()` on an `Err` value: "PoisonError { inner: .. }"

  ▶ TIMEOUT [expected PASS] /css21_dev/html4/margin-bottom-043.htm
  │
  │ VMware, Inc.
  │ Gallium 0.4 on softpipe
  └ 3.3 (Core Profile) Mesa 12.0.1

  ▶ TIMEOUT [expected PASS] /css21_dev/html4/margin-bottom-044.htm
  │
  │ VMware, Inc.
  │ Gallium 0.4 on softpipe
  └ 3.3 (Core Profile) Mesa 12.0.1

  ▶ TIMEOUT [expected PASS] /css21_dev/html4/margin-bottom-055.htm
  │
  │ VMware, Inc.
  │ Gallium 0.4 on softpipe
  └ 3.3 (Core Profile) Mesa 12.0.1

  ▶ TIMEOUT [expected PASS] /css21_dev/html4/margin-bottom-056.htm
  │
  │ VMware, Inc.
  │ Gallium 0.4 on softpipe
  └ 3.3 (Core Profile) Mesa 12.0.1

Ran 10198 tests finished in 1641.0 seconds.
  • 10181 ran as expected. 125 tests skipped.
  • 12 tests failed unexpectedly
  • 5 tests timed out unexpectedly

Not sure how to interpret these results. I loaded several of the tests up with ./mach run and they seemed to be correct (the images conformed to what the text said they should be.) And also none of the tests seem to have anything to do with my changes. Thoughts?

@glennw
Copy link
Member

glennw commented Mar 16, 2017

Those are probably intermittents unrelated to your change, I think. Did you run them in the release builder (the --release flag)? Also, did you run the WPT tests (they probably have more coverage relevant to this change, and can be run with ./mach test-wpt).

@squarewave
Copy link
Contributor Author

So, coincidentally I ran the wpt tests on my Macbook so I could do other things while they ran, and two gradient tests failed. I then ran the wrench tests on my Macbook and they don't display. Something about my Macbook doesn't seem to like the RGABU16 texture, and it just silently fails and reads 0,0,0,65535 (all black with full alpha), which is somewhat perplexing. Any thoughts?

The machine it works on is using an NVIDIA GTX 960, and the Macbook is running an AMD R9 M370DX. Is there anywhere that vendors document what is and isn't supported by their drivers or is it really the total chaos that it feels like?

@kvark
Copy link
Member

kvark commented Mar 16, 2017

@squarewave could you capture it with apitrace and share the result?

@squarewave
Copy link
Contributor Author

squarewave commented Mar 17, 2017

@kvark
Copy link
Member

kvark commented Mar 17, 2017

@squarewave thank you! I haven't found anything obviously wrong with either the code or the state in the capture. Do you mind sharing the repro steps? I have a mac at home, so I can check it out locally on the weekend.

@squarewave
Copy link
Contributor Author

squarewave commented Mar 17, 2017

Sure - I've just been doing this:

cd /path/to/wrench
cargo run show benchmarks/unaligned-gradient.yaml

You should then see a big black rectangle in the top left of the window.

@kvark
Copy link
Member

kvark commented Mar 20, 2017

@squarewave I ran it on Mac mini 2010. No black rectangle.

bors-servo pushed a commit that referenced this pull request Mar 24, 2017
added ordered dithering to gradient-like effects

Closes #929

It's a bit rough around the edges, so any criticism is completely welcome - just hoping to help out!

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/webrender/966)
<!-- Reviewable:end -->
@bors-servo
Copy link
Contributor

☀️ Test successful - status-travis
Approved by: kvark
Pushing 74bda66 to master...

@bors-servo bors-servo merged commit 6fa2881 into servo:master Mar 24, 2017
@glennw
Copy link
Member

glennw commented Mar 27, 2017

cc @kvark @squarewave

Unfortunately this seems to have broken the linear_gradients_parsing.html reftest in Servo. There's a few gradient related PRs recently, but it seems like this is the change that broke it, assuming I bisected correctly.

Would you be able to take a look and see what's causing the differences? I'll can hold off on updating WR in Servo for a bit, or we can temporarily revert this if it's going to take a while to sort out.

@staktrace
Copy link
Contributor

Also FYI this seems to have caused some reftest failures in Gecko, see https://bugzilla.mozilla.org/show_bug.cgi?id=1349692#c5 and subsequent comments. The reftest failures are caused by a few pixels having a slightly different value (visually I can't tell the difference) so we can just fuzz the difference in the reftest harness. However it might be indicative of a deeper problem, so just a heads-up for that.

@kvark
Copy link
Member

kvark commented Mar 27, 2017

@glennw @staktrace the PR does change the way of rendering gradients, so perhaps the image refs just need to be updated, given the new results are of better quality. I'm yet to look into the exact failures....

@squarewave
Copy link
Contributor Author

@staktrace This is my first patch in this area, so I don't know a lot about the reftests, but what units is "max difference" in? I see one of the tests failed with a max difference of 1, and the other failed with a max difference of 14. I would expect the maximum difference between a pixel with dithering and a pixel without dithering to be 1/256 (or 1 if not normalized) for each channel, so 14 seems to be above that. Otherwise, visually imperceptible differences are expected.

@staktrace
Copy link
Contributor

staktrace commented Mar 27, 2017

The "max difference" is the maximum difference in one of the (r,g,b) components. So if a pixel in one was rgb(1,1,1) and the corresponding pixel in the other was rgb(2,3,15) that would be a max difference of 14.

@staktrace
Copy link
Contributor

Also, with the reftests, if you click on the "bar chart" icon it will take you to the reftest analyzer where you can examine the differences in more detail. Here is one example: link

@squarewave
Copy link
Contributor Author

I'm a bit confused by what I'm seeing here. I would expect that on release, boxshadow-inset-large-offset-ref.html and boxshadow-inset-large-offset.html would be identical, but they're not. There's a visible difference on the left side of the div where the box shadow is fading out where it shouldn't be.

@kvark
Copy link
Member

kvark commented Mar 27, 2017

One thing that we can easily do in order to reduce the difference is to handle the case specifically when a gradient source = destination. If you look at the "linear_gradients_parsing_a.html", the rectangles there are just supposed to be filled with solid colors, so dithering doesn't give us much.

@staktrace
Copy link
Contributor

One thing to note about boxshadow-inset-large-offset is that it's already marked fuzzy with a max difference of 13 (and with 13612 pixels allowed to be fuzzy when webrender is enabled). So actually your patch just increased the fuzz difference from 13 to 14. Sorry for not checking that earlier.

@squarewave
Copy link
Contributor Author

Ah okay - then yeah both of these look good to me.

@kvark, if we're seeing any visual differences in a gradient where source == destination, then I think that's an indicator of a bug, since our dithering should only be able to push non-integer values up or down. If that's what you're seeing, I think the bug is in my dither function:

vec4 dither(vec4 color) {
    const int matrix_mask = 7;

    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);
}

I suspect it should be

float noise = (texelFetch(sDither, pos, 0).r - 0.5) * noise_factor;

so that we're pushing the value up or down by a value between 0 and 0.5, rather than pushing it up by a value between 0 and 1. I think my thought process was that it would be flooring the result in order to quantize it rather than rounding.

@kvark
Copy link
Member

kvark commented Mar 27, 2017

@squarewave oh, nice find! Hope that fixes everything :) looking forward to see your PR

@glennw
Copy link
Member

glennw commented Mar 28, 2017

There's also a number of WPT reftests that are new failures - I suspect they are the same issue as you've mentioned above - they are comparing gradients with flat colors to a solid color rectangle. Once we get the fix above in a PR, I'll run those WPT tests locally and make sure they become passes too :)

@squarewave
Copy link
Contributor Author

squarewave commented Mar 28, 2017

Quick update on this: last night I was digging pretty deep for little imperfections in this, and I managed to clear up all the things I saw, but I can't figure out why some of my solutions work. I can submit a PR with the changes and some comments documenting my confusion if you like.

Highlights:

  • I noticed that doing the bilinear filtering in two steps (with two linear samples and a mix) resolved an issue in which some transitions between shades were sharper than they should be, which is confusing because that should be equivalent to a single bilinear sample.
  • I had to offset the dither texture by 123.0 / 65535.0 instead of what I would expect it would be (0.5 / 255.0 -- half a step). When I offset it by 0.5 / 255.0, I'm left with one darker pixel out of the 64 pixels in the pattern. I had to keep dropping it down until all the dark pixels were gone, but not so far that light pixels started showing up. The value I landed on was 123.0 / 65535.0, which doesn't really hold any significance to me.

@kvark
Copy link
Member

kvark commented Mar 28, 2017

@squarewave we've got to dig it up and figure out why the expectations are wrong.

I bet something with the way colors are generated might be off. If the shader sampling is misbehaving, we might test it by forcing the colors to be black and white and measuring the result from a snapshot. I'm going to have another look at the code later today.

@squarewave
Copy link
Contributor Author

@kvark yeah I did quite a few experiments to try to coax the underlying problems out, so any help you can provide would be wonderful.

To avoid duplicating efforts, one thing I did notice is that there was a bug in my extract_bytes implementation due to the rounding. The new function is this:

    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,
        }
    }

With shift_by being 0 or 8.

moz-v2v-gh pushed a commit to mozilla/gecko-projects that referenced this pull request Mar 30, 2017
…. r=jrmuizel

The fuzziness was introduced by servo/webrender#966 and
might be fixed in the future, see discussion starting at
servo/webrender#966 (comment)

MozReview-Commit-ID: AIx6FY8XAiK
@kvark
Copy link
Member

kvark commented Mar 31, 2017

@squarewave I've found 2 things so far.

  1. The visible rough gradient transition in unaligned_gradient benchmark that you mentioned on IRC looks to be related to the interpolation of vOffset. Perhaps, not enough precision there? Using gl_FragCoord.y / window_size for the offset gives me perfect gradients. Also, the high/low bits look to blend correctly according to my tests (mixing black with white).

  2. the dithering noise is too high, which causes gradients between source==destination to be noisy. The factor should be (0.5/256.0) / (64.0/255.0) instead of 4.0/255.0, assuming the half-unit noise is desired.

edit - actual shader code:

    float normalization_factor = 255.0 / 64.0; // bring it into 0-1 range
    float noise_factor = 0.5 / 256.0; // half-unit difference noise
    float noise = texelFetch(sDither, pos, 0).r * (normalization_factor * noise_factor);

@kvark
Copy link
Member

kvark commented Mar 31, 2017

Eh, the noise factor is not that wrong, but there is a bit of fine logic missing. PR is incoming.

@kvark kvark mentioned this pull request Mar 31, 2017
bors-servo pushed a commit that referenced this pull request Apr 3, 2017
Proper dither re-enabled

Follow up to #966, reverts #1042
~~WIP - still being tested~~
cc @squarewave
r? @glennw

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/webrender/1045)
<!-- Reviewable:end -->
bors-servo pushed a commit that referenced this pull request Apr 3, 2017
Proper dither re-enabled

Follow up to #966, reverts #1042
~~WIP - still being tested~~
cc @squarewave
r? @glennw

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/webrender/1045)
<!-- Reviewable:end -->
Manishearth pushed a commit to Manishearth/gecko-dev that referenced this pull request Apr 5, 2017
…. r=jrmuizel

The fuzziness was introduced by servo/webrender#966 and
might be fixed in the future, see discussion starting at
servo/webrender#966 (comment)

MozReview-Commit-ID: AIx6FY8XAiK
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this pull request Oct 1, 2019
…. r=jrmuizel

The fuzziness was introduced by servo/webrender#966 and
might be fixed in the future, see discussion starting at
servo/webrender#966 (comment)

MozReview-Commit-ID: AIx6FY8XAiK

UltraBlame original commit: e0e0b41946f231db12a8d9584f7961022d96f8b9
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this pull request Oct 1, 2019
…. r=jrmuizel

The fuzziness was introduced by servo/webrender#966 and
might be fixed in the future, see discussion starting at
servo/webrender#966 (comment)

MozReview-Commit-ID: AIx6FY8XAiK

UltraBlame original commit: e0e0b41946f231db12a8d9584f7961022d96f8b9
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this pull request Oct 1, 2019
…. r=jrmuizel

The fuzziness was introduced by servo/webrender#966 and
might be fixed in the future, see discussion starting at
servo/webrender#966 (comment)

MozReview-Commit-ID: AIx6FY8XAiK

UltraBlame original commit: e0e0b41946f231db12a8d9584f7961022d96f8b9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants