Bug 1525420 - Use KHR_blend_equation_advanced for mix-blend mode implementation r=gw
authorDzmitry Malyshau <dmalyshau@mozilla.com>
Wed, 01 May 2019 20:45:22 +0000
changeset 530977 09753a1a153d348d456a0c785fcffeb9a77dd065
parent 530976 9ec9c4c0be3b7ab74b1ebaeb921ec62afa7691cd
child 530978 c2837abe3cd2b81c15071cdc99f5c0d45d294b06
child 531103 d338087034f7a26db10d1963a1d5f2ddd9e94051
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1525420
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1525420 - Use KHR_blend_equation_advanced for mix-blend mode implementation r=gw Use natively supported mix-blend modes, where appropriate. Disabled by default. Differential Revision: https://phabricator.services.mozilla.com/D26350
Cargo.lock
gfx/wr/Cargo.lock
gfx/wr/webrender/Cargo.toml
gfx/wr/webrender/src/batch.rs
gfx/wr/webrender/src/device/gl.rs
gfx/wr/webrender/src/frame_builder.rs
gfx/wr/webrender/src/picture.rs
gfx/wr/webrender/src/renderer.rs
gfx/wr/webrender/src/shade.rs
gfx/wr/webrender/src/tiling.rs
gfx/wr/wrench/reftests/blend/reftest.list
gfx/wr/wrench/src/wrench.rs
third_party/rust/gleam/.cargo-checksum.json
third_party/rust/gleam/Cargo.toml
third_party/rust/gleam/build.rs
third_party/rust/gleam/src/gl.rs
third_party/rust/gleam/src/gl_fns.rs
third_party/rust/gleam/src/gles_fns.rs
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1282,17 +1282,17 @@ source = "registry+https://github.com/ru
 dependencies = [
  "khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gleam"
-version = "0.6.16"
+version = "0.6.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "glob"
 version = "0.2.11"
@@ -3355,17 +3355,17 @@ dependencies = [
  "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "plane-split 0.13.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3410,17 +3410,17 @@ dependencies = [
  "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "nsstring 0.1.0",
  "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.60.0",
 ]
@@ -3702,17 +3702,17 @@ dependencies = [
 "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
 "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
 "checksum futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "884dbe32a6ae4cd7da5c6db9b78114449df9953b8d490c9d7e1b51720b922c62"
 "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
 "checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
 "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
 "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
 "checksum gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39a23d5e872a275135d66895d954269cf5e8661d234eb1c2480f4ce0d586acbd"
-"checksum gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "39bb69499005e11b7b7cc0af38404a1bc0f53d954bffa8adcdb6e8d5b14f75d5"
+"checksum gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7f46fd8874e043ffac0d638ed1567a2584f7814f6d72b4db37ab1689004a26c4"
 "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
 "checksum goblin 0.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "5911d7df7b8f65ab676c5327b50acea29d3c6a1a4ad05e444cf5dce321b26db2"
 "checksum guid_win 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87261686cc5e35b6584f4c2a430c2b153d8a92ab1ef820c16be34c1df8f5f58b"
 "checksum h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "a27e7ed946e8335bdf9a191bc1b9b14a03ba822d013d2f58437f4fabcbd7fc2c"
 "checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da"
 "checksum http 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "dca621d0fa606a5ff2850b6e337b57ad6137ee4d67e940449643ff45af6874c6"
 "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07"
 "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
--- a/gfx/wr/Cargo.lock
+++ b/gfx/wr/Cargo.lock
@@ -138,17 +138,17 @@ name = "cfg-if"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "cgl"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "clap"
 version = "2.31.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -365,17 +365,17 @@ dependencies = [
  "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "direct-composition"
 version = "0.1.0"
 dependencies = [
  "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.60.0",
  "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "winit 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "dlib"
@@ -564,17 +564,17 @@ source = "registry+https://github.com/ru
 dependencies = [
  "khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gleam"
-version = "0.6.16"
+version = "0.6.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "glutin"
 version = "0.17.0"
@@ -1640,17 +1640,17 @@ dependencies = [
  "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cstr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "pathfinder_font_renderer 0.5.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)",
@@ -1677,17 +1677,17 @@ dependencies = [
 
 [[package]]
 name = "webrender-examples"
 version = "0.1.0"
 dependencies = [
  "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "glutin 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.60.0",
  "winit 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender_api"
@@ -1794,17 +1794,17 @@ dependencies = [
  "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "font-loader 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "glutin 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "osmesa-src 0.1.1 (git+https://github.com/servo/osmesa-src)",
  "osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1941,17 +1941,17 @@ dependencies = [
 "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
 "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
 "checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
 "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
 "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
 "checksum gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3414b424657317e708489d2857d9575f4403698428b040b609b9d1c1a84a2c"
 "checksum gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39a23d5e872a275135d66895d954269cf5e8661d234eb1c2480f4ce0d586acbd"
 "checksum gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a795170cbd85b5a7baa58d6d7525cae6a03e486859860c220f7ebbbdd379d0a"
-"checksum gleam 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "39bb69499005e11b7b7cc0af38404a1bc0f53d954bffa8adcdb6e8d5b14f75d5"
+"checksum gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7f46fd8874e043ffac0d638ed1567a2584f7814f6d72b4db37ab1689004a26c4"
 "checksum glutin 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a70c5fe78efbd5a3b243a804ea1032053c584510f8822819f94cfb29b2100317"
 "checksum half 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d5c5f71a723d10dfc58927cbed37c3071a50afc7f073d86fd7d3e5727db890f"
 "checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37"
 "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
 "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
 "checksum image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "52fb0666a1273dac46f9725aa4859bcd5595fc3554cf3495051b4de8db745e7d"
 "checksum inflate 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec18d981200fd14e65ee8e35fb60ed1ce55227a02407303f3a72517c6146dcc"
 "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
--- a/gfx/wr/webrender/Cargo.toml
+++ b/gfx/wr/webrender/Cargo.toml
@@ -25,17 +25,17 @@ webrender_build = { version = "0.0.1", p
 [dependencies]
 base64 = { optional = true, version = "0.10" }
 bincode = "1.0"
 bitflags = "1.0"
 byteorder = "1.0"
 cfg-if = "0.1.2"
 cstr = "0.1.2"
 fxhash = "0.2.1"
-gleam = "0.6.16"
+gleam = "0.6.17"
 image = { optional = true, version = "0.21", default-features = false, features = ["png_codec"] }
 lazy_static = "1"
 log = "0.4"
 malloc_size_of_derive = "0.1"
 num-traits = "0.2"
 plane-split = "0.13.7"
 png = { optional = true, version = "0.14" }
 rayon = "1"
--- a/gfx/wr/webrender/src/batch.rs
+++ b/gfx/wr/webrender/src/batch.rs
@@ -133,25 +133,27 @@ fn textures_compatible(t1: TextureSource
     t1 == TextureSource::Invalid || t2 == TextureSource::Invalid || t1 == t2
 }
 
 pub struct AlphaBatchList {
     pub batches: Vec<PrimitiveBatch>,
     pub item_rects: Vec<Vec<PictureRect>>,
     current_batch_index: usize,
     current_z_id: ZBufferId,
+    break_advanced_blend_batches: bool,
 }
 
 impl AlphaBatchList {
-    fn new() -> Self {
+    fn new(break_advanced_blend_batches: bool) -> Self {
         AlphaBatchList {
             batches: Vec::new(),
             item_rects: Vec::new(),
             current_z_id: ZBufferId::invalid(),
             current_batch_index: usize::MAX,
+            break_advanced_blend_batches,
         }
     }
 
     pub fn set_params_and_get_batch(
         &mut self,
         key: BatchKey,
         bounding_rect: &PictureRect,
         z_id: ZBufferId,
@@ -175,16 +177,19 @@ impl AlphaBatchList {
                         }
 
                         if batch.key.is_compatible_with(&key) {
                             selected_batch_index = Some(batch_index);
                             break;
                         }
                     }
                 }
+                BlendMode::Advanced(_) if self.break_advanced_blend_batches => {
+                    // don't try to find a batch
+                }
                 _ => {
                     'outer_default: for (batch_index, batch) in self.batches.iter().enumerate().rev().take(10) {
                         // For normal batches, we only need to check for overlaps for batches
                         // other than the first batch we consider. If the first batch
                         // is compatible, then we know there isn't any potential overlap
                         // issues to worry about.
                         if batch.key.is_compatible_with(&key) {
                             selected_batch_index = Some(batch_index);
@@ -296,53 +301,39 @@ pub struct BatchList {
     pub tile_blits: Vec<TileBlit>,
 }
 
 impl BatchList {
     pub fn new(
         screen_size: DeviceIntSize,
         regions: Vec<DeviceIntRect>,
         tile_blits: Vec<TileBlit>,
+        break_advanced_blend_batches: bool,
     ) -> Self {
         // The threshold for creating a new batch is
         // one quarter the screen size.
         let batch_area_threshold = (screen_size.width * screen_size.height) as f32 / 4.0;
 
         BatchList {
-            alpha_batch_list: AlphaBatchList::new(),
+            alpha_batch_list: AlphaBatchList::new(break_advanced_blend_batches),
             opaque_batch_list: OpaqueBatchList::new(batch_area_threshold),
             regions,
             tile_blits,
         }
     }
 
     pub fn push_single_instance(
         &mut self,
         key: BatchKey,
         bounding_rect: &PictureRect,
         z_id: ZBufferId,
         instance: PrimitiveInstanceData,
     ) {
-        match key.blend_mode {
-            BlendMode::None => {
-                self.opaque_batch_list
-                    .set_params_and_get_batch(key, bounding_rect)
-                    .push(instance);
-            }
-            BlendMode::Alpha |
-            BlendMode::PremultipliedAlpha |
-            BlendMode::PremultipliedDestOut |
-            BlendMode::SubpixelConstantTextColor(..) |
-            BlendMode::SubpixelWithBgColor |
-            BlendMode::SubpixelDualSource => {
-                self.alpha_batch_list
-                    .set_params_and_get_batch(key, bounding_rect, z_id)
-                    .push(instance);
-            }
-        }
+        self.set_params_and_get_batch(key, bounding_rect, z_id)
+            .push(instance);
     }
 
     pub fn set_params_and_get_batch(
         &mut self,
         key: BatchKey,
         bounding_rect: &PictureRect,
         z_id: ZBufferId,
     ) -> &mut Vec<PrimitiveInstanceData> {
@@ -351,17 +342,18 @@ impl BatchList {
                 self.opaque_batch_list
                     .set_params_and_get_batch(key, bounding_rect)
             }
             BlendMode::Alpha |
             BlendMode::PremultipliedAlpha |
             BlendMode::PremultipliedDestOut |
             BlendMode::SubpixelConstantTextColor(..) |
             BlendMode::SubpixelWithBgColor |
-            BlendMode::SubpixelDualSource => {
+            BlendMode::SubpixelDualSource |
+            BlendMode::Advanced(_) => {
                 self.alpha_batch_list
                     .set_params_and_get_batch(key, bounding_rect, z_id)
             }
         }
     }
 
     fn finalize(&mut self) {
         self.opaque_batch_list.finalize()
@@ -470,48 +462,53 @@ struct SegmentInstanceData {
 }
 
 /// Encapsulates the logic of building batches for items that are blended.
 pub struct AlphaBatchBuilder {
     pub batch_lists: Vec<BatchList>,
     screen_size: DeviceIntSize,
     task_scissor_rect: Option<DeviceIntRect>,
     glyph_fetch_buffer: Vec<GlyphFetchResult>,
+    break_advanced_blend_batches: bool,
 }
 
 impl AlphaBatchBuilder {
     pub fn new(
         screen_size: DeviceIntSize,
         task_scissor_rect: Option<DeviceIntRect>,
+        break_advanced_blend_batches: bool,
     ) -> Self {
         let batch_lists = vec![
             BatchList::new(
                 screen_size,
                 Vec::new(),
                 Vec::new(),
+                break_advanced_blend_batches,
             ),
         ];
 
         AlphaBatchBuilder {
             batch_lists,
             task_scissor_rect,
             screen_size,
             glyph_fetch_buffer: Vec::new(),
+            break_advanced_blend_batches,
         }
     }
 
     fn push_new_batch_list(
         &mut self,
         regions: Vec<DeviceIntRect>,
         tile_blits: Vec<TileBlit>,
     ) {
         self.batch_lists.push(BatchList::new(
             self.screen_size,
             regions,
             tile_blits,
+            self.break_advanced_blend_batches,
         ));
     }
 
     fn current_batch_list(&mut self) -> &mut BatchList {
         self.batch_lists.last_mut().unwrap()
     }
 
     fn can_merge(&self) -> bool {
@@ -1097,16 +1094,20 @@ impl AlphaBatchBuilder {
                             brush_flags |= BrushFlags::PERSPECTIVE_INTERPOLATION;
                         };
 
                         let clip_task_address = ctx.get_prim_clip_task_address(
                             prim_info.clip_task_index,
                             render_tasks,
                         ).unwrap_or(OPAQUE_TASK_ADDRESS);
 
+                        let surface = ctx.surfaces[raster_config.surface_index.0]
+                            .surface
+                            .as_ref();
+
                         match raster_config.composite_mode {
                             PictureCompositeMode::TileCache { .. } => {
                                 let tile_cache = picture.tile_cache.as_ref().unwrap();
 
                                 // If the tile cache is disabled, just recurse into the
                                 // picture like a normal pass-through picture, adding
                                 // any child primitives into the parent surface batches.
                                 if !tile_cache.is_enabled {
@@ -1251,27 +1252,24 @@ impl AlphaBatchBuilder {
                                         self.push_new_batch_list(
                                             Vec::new(),
                                             Vec::new(),
                                         );
                                     }
                                 }
                             }
                             PictureCompositeMode::Filter(ref filter) => {
-                                let surface = ctx.surfaces[raster_config.surface_index.0]
-                                    .surface
-                                    .as_ref()
-                                    .expect("bug: surface must be allocated by now");
                                 assert!(filter.is_visible());
                                 match filter {
                                     FilterOp::Blur(..) => {
                                         let kind = BatchKind::Brush(
                                             BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
                                         );
                                         let (uv_rect_address, textures) = surface
+                                            .expect("bug: surface must be allocated by now")
                                             .resolve(
                                                 render_tasks,
                                                 ctx.resource_cache,
                                                 gpu_cache,
                                             );
                                         let key = BatchKey::new(
                                             kind,
                                             non_segmented_blend_mode,
@@ -1324,17 +1322,19 @@ impl AlphaBatchBuilder {
                                             ],
                                         };
 
                                         // Build batch keys for shadow/content
                                         let shadow_key = BatchKey::new(kind, non_segmented_blend_mode, shadow_textures);
                                         let content_key = BatchKey::new(kind, non_segmented_blend_mode, content_textures);
 
                                         // Retrieve the UV rect addresses for shadow/content.
-                                        let cache_task_id = surface.resolve_render_task_id();
+                                        let cache_task_id = surface
+                                            .expect("bug: surface must be allocated by now")
+                                            .resolve_render_task_id();
                                         let shadow_uv_rect_address = render_tasks[cache_task_id]
                                             .get_texture_address(gpu_cache)
                                             .as_int();
                                         let content_uv_rect_address = render_tasks[secondary_id]
                                             .get_texture_address(gpu_cache)
                                             .as_int();
 
                                         // Get the GPU cache address of the extra data handle.
@@ -1438,16 +1438,17 @@ impl AlphaBatchBuilder {
                                             }
                                             FilterOp::ColorMatrix(_) => {
                                                 picture.extra_gpu_data_handle.as_int(gpu_cache)
                                             }
                                             FilterOp::ComponentTransfer => unreachable!(),
                                         };
 
                                         let (uv_rect_address, textures) = surface
+                                            .expect("bug: surface must be allocated by now")
                                             .resolve(
                                                 render_tasks,
                                                 ctx.resource_cache,
                                                 gpu_cache,
                                             );
 
                                         let key = BatchKey::new(
                                             BatchKind::Brush(BrushBatchKind::Blend),
@@ -1479,32 +1480,27 @@ impl AlphaBatchBuilder {
                                         );
                                     }
                                 }
                             }
                             PictureCompositeMode::ComponentTransferFilter(handle) => {
                                 // This is basically the same as the general filter case above
                                 // except we store a little more data in the filter mode and
                                 // a gpu cache handle in the user data.
-                                let surface = ctx.surfaces[raster_config.surface_index.0]
-                                    .surface
-                                    .as_ref()
-                                    .expect("bug: surface must be allocated by now");
-
-
                                 let filter_data = &ctx.data_stores.filter_data[handle];
                                 let filter_mode : i32 = 13 |
                                     ((filter_data.data.r_func.to_int() << 28 |
                                       filter_data.data.g_func.to_int() << 24 |
                                       filter_data.data.b_func.to_int() << 20 |
                                       filter_data.data.a_func.to_int() << 16) as i32);
 
                                 let user_data = filter_data.gpu_cache_handle.as_int(gpu_cache);
 
                                 let (uv_rect_address, textures) = surface
+                                    .expect("bug: surface must be allocated by now")
                                     .resolve(
                                         render_tasks,
                                         ctx.resource_cache,
                                         gpu_cache,
                                     );
 
                                 let key = BatchKey::new(
                                     BatchKind::Brush(BrushBatchKind::Blend),
@@ -1530,22 +1526,58 @@ impl AlphaBatchBuilder {
 
                                 self.current_batch_list().push_single_instance(
                                     key,
                                     bounding_rect,
                                     z_id,
                                     PrimitiveInstanceData::from(instance),
                                 );
                             }
+                            PictureCompositeMode::MixBlend(mode) if ctx.use_advanced_blending => {
+                                let (uv_rect_address, textures) = surface
+                                    .expect("bug: surface must be allocated by now")
+                                    .resolve(
+                                        render_tasks,
+                                        ctx.resource_cache,
+                                        gpu_cache,
+                                    );
+                                let key = BatchKey::new(
+                                    BatchKind::Brush(
+                                        BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
+                                    ),
+                                    BlendMode::Advanced(mode),
+                                    textures,
+                                );
+                                let prim_header_index = prim_headers.push(&prim_header, z_id, [
+                                    ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
+                                    RasterizationSpace::Local as i32,
+                                    get_shader_opacity(1.0),
+                                    0,
+                                ]);
+
+                                let instance = BrushInstance {
+                                    prim_header_index,
+                                    clip_task_address,
+                                    segment_index: INVALID_SEGMENT_INDEX,
+                                    edge_flags: EdgeAaSegmentMask::empty(),
+                                    brush_flags,
+                                    user_data: uv_rect_address.as_int(),
+                                };
+
+                                self.current_batch_list().push_single_instance(
+                                    key,
+                                    bounding_rect,
+                                    z_id,
+                                    PrimitiveInstanceData::from(instance),
+                                );
+                            }
                             PictureCompositeMode::MixBlend(mode) => {
-                                let surface = ctx.surfaces[raster_config.surface_index.0]
-                                    .surface
-                                    .as_ref()
-                                    .expect("bug: surface must be allocated by now");
-                                let cache_task_id = surface.resolve_render_task_id();
+                                let cache_task_id = surface
+                                    .expect("bug: surface must be allocated by now")
+                                    .resolve_render_task_id();
                                 let backdrop_id = picture.secondary_render_task_id.expect("no backdrop!?");
 
                                 let key = BatchKey::new(
                                     BatchKind::Brush(
                                         BrushBatchKind::MixBlend {
                                             task_id,
                                             source_id: cache_task_id,
                                             backdrop_id,
@@ -1575,21 +1607,19 @@ impl AlphaBatchBuilder {
                                 self.current_batch_list().push_single_instance(
                                     key,
                                     bounding_rect,
                                     z_id,
                                     PrimitiveInstanceData::from(instance),
                                 );
                             }
                             PictureCompositeMode::Blit(_) => {
-                                let surface = ctx.surfaces[raster_config.surface_index.0]
-                                    .surface
-                                    .as_ref()
-                                    .expect("bug: surface must be allocated by now");
-                                let cache_task_id = surface.resolve_render_task_id();
+                                let cache_task_id = surface
+                                    .expect("bug: surface must be allocated by now")
+                                    .resolve_render_task_id();
                                 let uv_rect_address = render_tasks[cache_task_id]
                                     .get_texture_address(gpu_cache)
                                     .as_int();
                                 let batch_params = BrushBatchParameters::shared(
                                     BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
                                     BatchTextures::render_target_cache(),
                                     [
                                         ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
--- a/gfx/wr/webrender/src/device/gl.rs
+++ b/gfx/wr/webrender/src/device/gl.rs
@@ -1,15 +1,15 @@
 /* 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/. */
 
 use super::super::shader_source::SHADERS;
 use api::{ColorF, ImageDescriptor, ImageFormat, MemoryReport};
-use api::{TextureTarget, VoidPtrToSizeFn};
+use api::{MixBlendMode, TextureTarget, VoidPtrToSizeFn};
 use api::units::*;
 use euclid::Transform3D;
 use gleam::gl;
 use internal_types::{FastHashMap, LayerIndex, RenderTargetInfo};
 use log::Level;
 use profiler;
 use sha2::{Digest, Sha256};
 use smallvec::SmallVec;
@@ -3047,16 +3047,41 @@ impl Device {
         self.gl.blend_func(gl::ONE, gl::ONE_MINUS_SRC1_COLOR);
         self.gl.blend_equation(gl::FUNC_ADD);
     }
     pub fn set_blend_mode_show_overdraw(&self) {
         self.gl.blend_func(gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
         self.gl.blend_equation(gl::FUNC_ADD);
     }
 
+    pub fn set_blend_mode_advanced(&self, mode: MixBlendMode) {
+        self.gl.blend_equation(match mode {
+            MixBlendMode::Normal => {
+                // blend factor only make sense for the normal mode
+                self.gl.blend_func_separate(gl::ZERO, gl::SRC_COLOR, gl::ZERO, gl::SRC_ALPHA);
+                gl::FUNC_ADD
+            },
+            MixBlendMode::Multiply => gl::MULTIPLY_KHR,
+            MixBlendMode::Screen => gl::SCREEN_KHR,
+            MixBlendMode::Overlay => gl::OVERLAY_KHR,
+            MixBlendMode::Darken => gl::DARKEN_KHR,
+            MixBlendMode::Lighten => gl::LIGHTEN_KHR,
+            MixBlendMode::ColorDodge => gl::COLORDODGE_KHR,
+            MixBlendMode::ColorBurn => gl::COLORBURN_KHR,
+            MixBlendMode::HardLight => gl::HARDLIGHT_KHR,
+            MixBlendMode::SoftLight => gl::SOFTLIGHT_KHR,
+            MixBlendMode::Difference => gl::DIFFERENCE_KHR,
+            MixBlendMode::Exclusion => gl::EXCLUSION_KHR,
+            MixBlendMode::Hue => gl::HSL_HUE_KHR,
+            MixBlendMode::Saturation => gl::HSL_SATURATION_KHR,
+            MixBlendMode::Color => gl::HSL_COLOR_KHR,
+            MixBlendMode::Luminosity => gl::HSL_LUMINOSITY_KHR,
+        });
+    }
+
     pub fn supports_extension(&self, extension: &str) -> bool {
         supports_extension(&self.extensions, extension)
     }
 
     /// Enable the pixel local storage functionality. Caller must
     /// have already confirmed the device supports this.
     pub fn enable_pixel_local_storage(&mut self, enable: bool) {
         debug_assert!(self.capabilities.supports_pixel_local_storage);
--- a/gfx/wr/webrender/src/frame_builder.rs
+++ b/gfx/wr/webrender/src/frame_builder.rs
@@ -41,28 +41,30 @@ pub enum ChasePrimitive {
 }
 
 impl Default for ChasePrimitive {
     fn default() -> Self {
         ChasePrimitive::Nothing
     }
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct FrameBuilderConfig {
     pub default_font_render_mode: FontRenderMode,
     pub dual_source_blending_is_supported: bool,
     pub dual_source_blending_is_enabled: bool,
     pub chase_primitive: ChasePrimitive,
     pub enable_picture_caching: bool,
     /// True if we're running tests (i.e. via wrench).
     pub testing: bool,
     pub gpu_supports_fast_clears: bool,
+    pub gpu_supports_advanced_blend: bool,
+    pub advanced_blend_is_coherent: bool,
 }
 
 /// A set of common / global resources that are retained between
 /// new display lists, such that any GPU cache handles can be
 /// persisted even when a new display list arrives.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct FrameGlobalResources {
     /// The image shader block for the most common / default
@@ -216,16 +218,18 @@ impl FrameBuilder {
             config: FrameBuilderConfig {
                 default_font_render_mode: FontRenderMode::Mono,
                 dual_source_blending_is_enabled: true,
                 dual_source_blending_is_supported: false,
                 chase_primitive: ChasePrimitive::Nothing,
                 enable_picture_caching: false,
                 testing: false,
                 gpu_supports_fast_clears: false,
+                gpu_supports_advanced_blend: false,
+                advanced_blend_is_coherent: false,
             },
         }
     }
 
     /// Provide any cached surface tiles from the previous frame builder
     /// to a new frame builder. These will be consumed or dropped the
     /// first time a new frame builder creates a frame.
     pub fn set_retained_resources(
@@ -579,16 +583,18 @@ impl FrameBuilder {
                                            self.config.dual_source_blending_is_supported;
 
             for pass in &mut passes {
                 let mut ctx = RenderTargetContext {
                     global_device_pixel_scale,
                     prim_store: &self.prim_store,
                     resource_cache,
                     use_dual_source_blending,
+                    use_advanced_blending: self.config.gpu_supports_advanced_blend,
+                    break_advanced_blend_batches: !self.config.advanced_blend_is_coherent,
                     clip_scroll_tree,
                     data_stores,
                     surfaces: &surfaces,
                     scratch,
                     screen_world_rect,
                     globals: &self.globals,
                 };
 
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -3098,17 +3098,17 @@ impl PicturePrimitive {
 
                     // segment rect / extra data
                     request.push(shadow_rect);
                     request.push([0.0, 0.0, 0.0, 0.0]);
                 }
 
                 PictureSurface::RenderTask(render_task_id)
             }
-            PictureCompositeMode::MixBlend(..) => {
+            PictureCompositeMode::MixBlend(..) if !frame_context.fb_config.gpu_supports_advanced_blend => {
                 let uv_rect_kind = calculate_uv_rect_kind(
                     &pic_rect,
                     &transform,
                     &clipped,
                     device_pixel_scale,
                     true,
                 );
 
@@ -3188,16 +3188,17 @@ impl PicturePrimitive {
                     pic_context.raster_spatial_node_index,
                     device_pixel_scale,
                 );
 
                 let render_task_id = frame_state.render_tasks.add(picture_task);
                 frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
                 PictureSurface::RenderTask(render_task_id)
             }
+            PictureCompositeMode::MixBlend(..) |
             PictureCompositeMode::Blit(_) => {
                 // The SplitComposite shader used for 3d contexts doesn't snap
                 // to pixels, so we shouldn't snap our uv coordinates either.
                 let supports_snapping = match self.context_3d {
                     Picture3DContext::In{ .. } => false,
                     _ => true,
                 };
 
--- a/gfx/wr/webrender/src/renderer.rs
+++ b/gfx/wr/webrender/src/renderer.rs
@@ -29,17 +29,17 @@
 //!   - for rasterized primitives, the orthographics projection transforms
 //! the content rectangle to -1 to 1
 //!   - the viewport transformation is setup to map the whole range to
 //! the framebuffer rectangle provided by the document view, stored in `DrawTarget`
 //!   - all the direct framebuffer operations, like blitting, reading pixels, and setting
 //! up the scissor, are accepting already transformed coordinates, which we can get by
 //! calling `DrawTarget::to_framebuffer_rect`
 
-use api::{ApiMsg, BlobImageHandler, ColorF, ColorU};
+use api::{ApiMsg, BlobImageHandler, ColorF, ColorU, MixBlendMode};
 use api::{DocumentId, Epoch, ExternalImageId};
 use api::{ExternalImageType, FontRenderMode, FrameMsg, ImageFormat, PipelineId};
 use api::{ImageRendering, Checkpoint, NotificationRequest};
 use api::{DebugCommand, MemoryReport, VoidPtrToSizeFn};
 use api::{RenderApiSender, RenderNotifier, TextureTarget};
 use api::channel;
 use api::units::*;
 pub use api::DebugFlags;
@@ -1109,16 +1109,17 @@ impl TextureResolver {
 pub enum BlendMode {
     None,
     Alpha,
     PremultipliedAlpha,
     PremultipliedDestOut,
     SubpixelDualSource,
     SubpixelConstantTextColor(ColorF),
     SubpixelWithBgColor,
+    Advanced(MixBlendMode),
 }
 
 /// Tracks the state of each row in the GPU cache texture.
 struct CacheRow {
     /// Mirrored block data on CPU for this row. We store a copy of
     /// the data on the CPU side to improve upload batching.
     cpu_blocks: Box<[GpuBlockData; MAX_VERTEX_TEXTURE_WIDTH]>,
     /// True if this row is dirty.
@@ -1859,16 +1860,18 @@ pub struct Renderer {
     shaders: Rc<RefCell<Shaders>>,
 
     pub gpu_glyph_renderer: GpuGlyphRenderer,
 
     max_recorded_profiles: usize,
 
     clear_color: Option<ColorF>,
     enable_clear_scissor: bool,
+    enable_advanced_blend_barriers: bool,
+
     debug: LazyInitializedDebugRenderer,
     debug_flags: DebugFlags,
     backend_profile_counters: BackendProfileCounters,
     profile_counters: RendererProfileCounters,
     resource_upload_time: u64,
     gpu_cache_upload_time: u64,
     profiler: Profiler,
     new_frame_indicator: ChangeIndicator,
@@ -2017,20 +2020,25 @@ impl Renderer {
 
         let supports_dual_source_blending = match gl_type {
             gl::GlType::Gl => device.supports_extension("GL_ARB_blend_func_extended") &&
                 device.supports_extension("GL_ARB_explicit_attrib_location"),
             gl::GlType::Gles => device.supports_extension("GL_EXT_blend_func_extended"),
         };
         let use_dual_source_blending =
             supports_dual_source_blending &&
-            !options.disable_dual_source_blending &&
+            options.allow_dual_source_blending &&
             // If using pixel local storage, subpixel AA isn't supported (we disable it on all
             // mobile devices explicitly anyway).
             !device.get_capabilities().supports_pixel_local_storage;
+        let ext_blend_equation_advanced =
+            options.allow_advanced_blend_equation &&
+            device.supports_extension("GL_KHR_blend_equation_advanced");
+        let ext_blend_equation_advanced_coherent =
+            device.supports_extension("GL_KHR_blend_equation_advanced_coherent");
 
         // 512 is the minimum that the texture cache can work with.
         const MIN_TEXTURE_SIZE: i32 = 512;
         if let Some(user_limit) = options.max_texture_size {
             assert!(user_limit >= MIN_TEXTURE_SIZE);
             device.clamp_max_texture_size(user_limit);
         }
         if device.max_texture_size() < MIN_TEXTURE_SIZE {
@@ -2196,17 +2204,20 @@ impl Renderer {
         let config = FrameBuilderConfig {
             default_font_render_mode,
             dual_source_blending_is_enabled: true,
             dual_source_blending_is_supported: use_dual_source_blending,
             chase_primitive: options.chase_primitive,
             enable_picture_caching: options.enable_picture_caching,
             testing: options.testing,
             gpu_supports_fast_clears: options.gpu_supports_fast_clears,
+            gpu_supports_advanced_blend: ext_blend_equation_advanced,
+            advanced_blend_is_coherent: ext_blend_equation_advanced_coherent,
         };
+        info!("WR {:?}", config);
 
         let device_pixel_ratio = options.device_pixel_ratio;
         let debug_flags = options.debug_flags;
         let payload_rx_for_backend = payload_rx.to_mpsc_receiver();
         let size_of_op = options.size_of_op;
         let enclosing_size_of_op = options.enclosing_size_of_op;
         let make_size_of_ops =
             move || size_of_op.map(|o| MallocSizeOfOps::new(o, enclosing_size_of_op));
@@ -2372,16 +2383,17 @@ impl Renderer {
             gpu_cache_upload_time: 0,
             profiler: Profiler::new(),
             new_frame_indicator: ChangeIndicator::new(),
             new_scene_indicator: ChangeIndicator::new(),
             slow_frame_indicator: ChangeIndicator::new(),
             max_recorded_profiles: options.max_recorded_profiles,
             clear_color: options.clear_color,
             enable_clear_scissor: options.enable_clear_scissor,
+            enable_advanced_blend_barriers: !ext_blend_equation_advanced_coherent,
             last_time: 0,
             gpu_profile,
             gpu_glyph_renderer,
             vaos: RendererVAOs {
                 prim_vao,
                 blur_vao,
                 clip_vao,
                 border_vao,
@@ -3894,16 +3906,22 @@ impl Renderer {
                                 // Using the three pass "component alpha with font smoothing
                                 // background color" rendering technique:
                                 //
                                 // /webrender/doc/text-rendering.md
                                 //
                                 self.device.set_blend_mode_subpixel_with_bg_color_pass0();
                                 self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass0 as _);
                             }
+                            BlendMode::Advanced(mode) => {
+                                if self.enable_advanced_blend_barriers {
+                                    self.device.gl().blend_barrier_khr();
+                                }
+                                self.device.set_blend_mode_advanced(mode);
+                            }
                         }
                         prev_blend_mode = batch.key.blend_mode;
                     }
 
                     // Handle special case readback for composites.
                     if let BatchKind::Brush(BrushBatchKind::MixBlend { task_id, source_id, backdrop_id }) = batch.key.kind {
                         // composites can't be grouped together because
                         // they may overlap and affect each other.
@@ -5597,29 +5615,30 @@ pub struct RendererOptions {
     pub blob_image_handler: Option<Box<BlobImageHandler>>,
     pub recorder: Option<Box<ApiRecordingReceiver>>,
     pub thread_listener: Option<Box<ThreadListener + Send + Sync>>,
     pub size_of_op: Option<VoidPtrToSizeFn>,
     pub enclosing_size_of_op: Option<VoidPtrToSizeFn>,
     pub cached_programs: Option<Rc<ProgramCache>>,
     pub debug_flags: DebugFlags,
     pub renderer_id: Option<u64>,
-    pub disable_dual_source_blending: bool,
     pub scene_builder_hooks: Option<Box<SceneBuilderHooks + Send>>,
     pub sampler: Option<Box<AsyncPropertySampler + Send>>,
     pub chase_primitive: ChasePrimitive,
     pub support_low_priority_transactions: bool,
     pub namespace_alloc_by_client: bool,
     pub enable_picture_caching: bool,
     pub testing: bool,
     /// Set to true if this GPU supports hardware fast clears as a performance
     /// optimization. Likely requires benchmarking on various GPUs to see if
     /// it is a performance win. The default is false, which tends to be best
     /// performance on lower end / integrated GPUs.
     pub gpu_supports_fast_clears: bool,
+    pub allow_dual_source_blending: bool,
+    pub allow_advanced_blend_equation: bool,
     /// If true, allow WR to use pixel local storage if the device supports it.
     /// For now, this defaults to false since the code is still experimental
     /// and not complete. This option will probably be removed once support is
     /// complete, and WR can implicitly choose whether to make use of PLS.
     pub allow_pixel_local_storage_support: bool,
     /// Start the debug server for this renderer.
     pub start_debug_server: bool,
 }
@@ -5647,25 +5666,26 @@ impl Default for RendererOptions {
             workers: None,
             blob_image_handler: None,
             recorder: None,
             thread_listener: None,
             size_of_op: None,
             enclosing_size_of_op: None,
             renderer_id: None,
             cached_programs: None,
-            disable_dual_source_blending: false,
             scene_builder_hooks: None,
             sampler: None,
             chase_primitive: ChasePrimitive::Nothing,
             support_low_priority_transactions: false,
             namespace_alloc_by_client: false,
             enable_picture_caching: false,
             testing: false,
             gpu_supports_fast_clears: false,
+            allow_dual_source_blending: false,
+            allow_advanced_blend_equation: false,
             allow_pixel_local_storage_support: false,
             // For backwards compatibility we set this to true by default, so
             // that if the debugger feature is enabled, the debug server will
             // be started automatically. Users can explicitly disable this as
             // needed.
             start_debug_server: true,
         }
     }
--- a/gfx/wr/webrender/src/shade.rs
+++ b/gfx/wr/webrender/src/shade.rs
@@ -336,17 +336,18 @@ impl BrushShader {
            -> &mut LazilyCompiledShader {
         match blend_mode {
             _ if debug_flags.contains(DebugFlags::SHOW_OVERDRAW) => &mut self.debug_overdraw,
             BlendMode::None => &mut self.opaque,
             BlendMode::Alpha |
             BlendMode::PremultipliedAlpha |
             BlendMode::PremultipliedDestOut |
             BlendMode::SubpixelConstantTextColor(..) |
-            BlendMode::SubpixelWithBgColor => &mut self.alpha,
+            BlendMode::SubpixelWithBgColor |
+            BlendMode::Advanced(_) => &mut self.alpha,
             BlendMode::SubpixelDualSource => {
                 self.dual_source
                     .as_mut()
                     .expect("bug: no dual source shader loaded")
             }
         }
     }
 
@@ -676,20 +677,20 @@ impl Shaders {
         }
 
         let ps_text_run = TextShader::new("ps_text_run",
             device,
             &extra_features,
             options.precache_flags,
         )?;
 
-        let dual_source_precache_flags = if options.disable_dual_source_blending {
+        let dual_source_precache_flags = if options.allow_dual_source_blending {
+            options.precache_flags
+        } else {
             ShaderPrecacheFlags::empty()
-        } else {
-            options.precache_flags
         };
 
         let ps_text_run_dual_source = TextShader::new("ps_text_run",
             device,
             &[DUAL_SOURCE_FEATURE],
             dual_source_precache_flags,
         )?;
 
@@ -714,17 +715,17 @@ impl Shaders {
                 if feature_string != "" {
                     image_features.push(feature_string);
                 }
                 brush_image[buffer_kind] = Some(BrushShader::new(
                     "brush_image",
                     device,
                     &image_features,
                     options.precache_flags,
-                    !options.disable_dual_source_blending,
+                    options.allow_dual_source_blending,
                     use_pixel_local_storage,
                 )?);
             }
             image_features.clear();
         }
 
         // All yuv_image configuration.
         let mut yuv_features = Vec::new();
--- a/gfx/wr/webrender/src/tiling.rs
+++ b/gfx/wr/webrender/src/tiling.rs
@@ -51,16 +51,18 @@ const TEXTURE_DIMENSION_MASK: i32 = 0xFF
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct RenderTargetIndex(pub usize);
 
 pub struct RenderTargetContext<'a, 'rc> {
     pub global_device_pixel_scale: DevicePixelScale,
     pub prim_store: &'a PrimitiveStore,
     pub resource_cache: &'rc mut ResourceCache,
     pub use_dual_source_blending: bool,
+    pub use_advanced_blending: bool,
+    pub break_advanced_blend_batches: bool,
     pub clip_scroll_tree: &'a ClipScrollTree,
     pub data_stores: &'a DataStores,
     pub surfaces: &'a [SurfaceInfo],
     pub scratch: &'a PrimitiveScratchBuffer,
     pub screen_world_rect: WorldRect,
     pub globals: &'a FrameGlobalResources,
 }
 
@@ -427,16 +429,17 @@ impl RenderTarget for ColorRenderTarget 
                         None
                     } else {
                         Some(target_rect)
                     };
 
                     let mut batch_builder = AlphaBatchBuilder::new(
                         self.screen_size,
                         scisor_rect,
+                        ctx.break_advanced_blend_batches,
                     );
 
                     batch_builder.add_pic_to_batch(
                         pic,
                         *task_id,
                         ctx,
                         gpu_cache,
                         render_tasks,
--- a/gfx/wr/wrench/reftests/blend/reftest.list
+++ b/gfx/wr/wrench/reftests/blend/reftest.list
@@ -1,13 +1,13 @@
 == multiply.yaml multiply-ref.yaml
 == multiply-2.yaml multiply-2-ref.yaml
 == color_targets(3) alpha_targets(0) multiply-3.yaml multiply-2-ref.yaml
 == difference.yaml difference-ref.yaml
-fuzzy(1,10000) == difference-transparent.yaml difference-transparent-ref.yaml
+fuzzy(1,30000) == difference-transparent.yaml difference-transparent-ref.yaml
 == darken.yaml darken-ref.yaml
 == lighten.yaml lighten-ref.yaml
 
 == repeated-difference.yaml repeated-difference-ref.yaml
 
 == isolated.yaml isolated-ref.yaml
 == isolated-2.yaml isolated-2-ref.yaml
 == isolated-with-filter.yaml isolated-ref.yaml
--- a/gfx/wr/wrench/src/wrench.rs
+++ b/gfx/wr/wrench/src/wrench.rs
@@ -213,21 +213,22 @@ impl Wrench {
             resource_override_path: shader_override_path,
             recorder,
             enable_subpixel_aa: !no_subpixel_aa,
             debug_flags,
             enable_clear_scissor: !no_scissor,
             max_recorded_profiles: 16,
             precache_flags,
             blob_image_handler: Some(Box::new(blob::CheckerboardRenderer::new(callbacks.clone()))),
-            disable_dual_source_blending,
             chase_primitive,
             enable_picture_caching: true,
             testing: true,
             max_texture_size: Some(8196), // Needed for rawtest::test_resize_image.
+            allow_dual_source_blending: !disable_dual_source_blending,
+            allow_advanced_blend_equation: true,
             ..Default::default()
         };
 
         // put an Awakened event into the queue to kick off the first frame
         if let Some(ref _elp) = proxy {
             #[cfg(not(target_os = "android"))]
             let _ = _elp.wakeup();
         }
--- a/third_party/rust/gleam/.cargo-checksum.json
+++ b/third_party/rust/gleam/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"COPYING":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"6bf850af90d5a3828cf26170a161f2ed06fa3cf3783dce79d28fe6444654408e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"1acb12040be43a3582d5897f11870b3ffdcd7ce0f4f32de158175bb6b33ec0b7","build.rs":"6ee689b1edfcd469dea669b0dc11ca89e0172c3b58bb82ff7a58acc94e1f7e88","rustfmt.toml":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/gl.rs":"2663b598573f7521d06f878229eee65434c831cf9fd4b543b4fcdd3bb1b281aa","src/gl_fns.rs":"239ace5607ee8dd4bcad35db0c4908469d7deb4841c162f736e404e1403980f7","src/gles_fns.rs":"51f25388f092242fb25bfe4861e70690006f4ac28e854d709ebb440cbef3df03","src/lib.rs":"16610c19b45a3f26d56b379a3591aa2e4fc9477e7bd88f86b31c6ea32e834861"},"package":"39bb69499005e11b7b7cc0af38404a1bc0f53d954bffa8adcdb6e8d5b14f75d5"}
\ No newline at end of file
+{"files":{"COPYING":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"40dda1b03ff20d8a3b4b544683f37a8d2b2137cfbb4d545122167352690d6b16","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"1acb12040be43a3582d5897f11870b3ffdcd7ce0f4f32de158175bb6b33ec0b7","build.rs":"2d3833a24fee9d1f669f4cd7347b4ca8444a138d473ab9188f4d65f6981c4191","rustfmt.toml":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/gl.rs":"b7791f77dbbea690a7a0d33e3c083337a6b04a233a192dc8c96d4fe481a4a7ed","src/gl_fns.rs":"f88cd940691e0fca169cabbe2a95418300d09392d91a020079cfbdd5bacd753b","src/gles_fns.rs":"3766f2b76aa4038774a4754ce89cdcbb50286ab5bcf07cb0bb6e88f0de31f96f","src/lib.rs":"16610c19b45a3f26d56b379a3591aa2e4fc9477e7bd88f86b31c6ea32e834861"},"package":"7f46fd8874e043ffac0d638ed1567a2584f7814f6d72b4db37ab1689004a26c4"}
\ No newline at end of file
--- a/third_party/rust/gleam/Cargo.toml
+++ b/third_party/rust/gleam/Cargo.toml
@@ -1,23 +1,23 @@
 # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
 #
 # When uploading crates to the registry Cargo will automatically
 # "normalize" Cargo.toml files for maximal compatibility
 # with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g. crates.io) dependencies
+# to registry (e.g., crates.io) dependencies
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "gleam"
-version = "0.6.16"
+version = "0.6.17"
 authors = ["The Servo Project Developers"]
 build = "build.rs"
 description = "Generated OpenGL bindings and wrapper for Servo."
 documentation = "https://doc.servo.org/gleam/"
 license = "Apache-2.0/MIT"
 repository = "https://github.com/servo/gleam"
 [build-dependencies.gl_generator]
 version = "0.11"
--- a/third_party/rust/gleam/build.rs
+++ b/third_party/rust/gleam/build.rs
@@ -21,16 +21,18 @@ fn main() {
         "GL_ARB_copy_image",
         "GL_ARB_get_program_binary",
         "GL_ARB_invalidate_subdata",
         "GL_ARB_texture_rectangle",
         "GL_ARB_texture_storage",
         "GL_EXT_debug_marker",
         "GL_EXT_texture_filter_anisotropic",
         "GL_KHR_debug",
+        "GL_KHR_blend_equation_advanced",
+        "GL_KHR_blend_equation_advanced_coherent",
     ];
     let gl_reg = Registry::new(
         Api::Gl,
         (3, 3),
         Profile::Compatibility,
         Fallbacks::All,
         gl_extensions,
     );
@@ -42,22 +44,24 @@ fn main() {
     let gles_extensions = [
         "GL_EXT_copy_image",
         "GL_EXT_debug_marker",
         "GL_EXT_disjoint_timer_query",
         "GL_EXT_shader_texture_lod",
         "GL_EXT_texture_filter_anisotropic",
         "GL_EXT_texture_format_BGRA8888",
         "GL_EXT_texture_storage",
-        "GL_KHR_debug",
         "GL_OES_EGL_image_external",
         "GL_OES_EGL_image",
         "GL_OES_texture_half_float",
         "GL_EXT_shader_pixel_local_storage",
         "GL_ANGLE_provoking_vertex",
+        "GL_KHR_debug",
+        "GL_KHR_blend_equation_advanced",
+        "GL_KHR_blend_equation_advanced_coherent",
     ];
     let gles_reg = Registry::new(
         Api::Gles2,
         (3, 0),
         Profile::Core,
         Fallbacks::All,
         gles_extensions,
     );
--- a/third_party/rust/gleam/src/gl.rs
+++ b/third_party/rust/gleam/src/gl.rs
@@ -563,16 +563,18 @@ declare_gl_apis! {
     fn texture_range_apple(&self, target: GLenum, data: &[u8]);
     fn gen_fences_apple(&self, n: GLsizei) -> Vec<GLuint>;
     fn delete_fences_apple(&self, fences: &[GLuint]);
     fn set_fence_apple(&self, fence: GLuint);
     fn finish_fence_apple(&self, fence: GLuint);
     fn test_fence_apple(&self, fence: GLuint);
     fn test_object_apple(&self, object: GLenum, name: GLuint) -> GLboolean;
     fn finish_object_apple(&self, object: GLenum, name: GLuint);
+    // GL_KHR_blend_equation_advanced
+    fn blend_barrier_khr(&self);
 
     // GL_ARB_blend_func_extended
     fn bind_frag_data_location_indexed(
         &self,
         program: GLuint,
         color_number: GLuint,
         index: GLuint,
         name: &str,
--- a/third_party/rust/gleam/src/gl_fns.rs
+++ b/third_party/rust/gleam/src/gl_fns.rs
@@ -2139,9 +2139,18 @@ impl Gl for GlFns {
                 return output;
             }
         }
     }
 
     fn provoking_vertex_angle(&self, _mode: GLenum) {
         unimplemented!("This extension is GLES only");
     }
+
+    // GL_KHR_blend_equation_advanced
+    fn blend_barrier_khr(&self) {
+        if self.ffi_gl_.BlendBarrierKHR.is_loaded() {
+            unsafe {
+                self.ffi_gl_.BlendBarrierKHR();
+            }
+        }
+    }
 }
--- a/third_party/rust/gleam/src/gles_fns.rs
+++ b/third_party/rust/gleam/src/gles_fns.rs
@@ -2106,9 +2106,18 @@ impl Gl for GlesFns {
         }
     }
 
     fn provoking_vertex_angle(&self, mode: GLenum) {
         unsafe {
             self.ffi_gl_.ProvokingVertexANGLE(mode);
         }
     }
+
+    // GL_KHR_blend_equation_advanced
+    fn blend_barrier_khr(&self) {
+        if self.ffi_gl_.BlendBarrierKHR.is_loaded() {
+            unsafe {
+                self.ffi_gl_.BlendBarrierKHR();
+            }
+        }
+    }
 }