1/* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5#define VECS_PER_SPECIFIC_BRUSH 3 6 7#include shared,prim_shared,brush 8 9// Interpolated UV coordinates to sample. 10varying vec2 vUv; 11 12// X = layer index to sample, Y = flag to allow perspective interpolation of UV. 13flat varying vec2 vLayerAndPerspective; 14flat varying float vAmount; 15flat varying int vOp; 16flat varying mat3 vColorMat; 17flat varying vec3 vColorOffset; 18flat varying vec4 vUvClipBounds; 19 20#ifdef WR_VERTEX_SHADER 21 22void brush_vs( 23 VertexInfo vi, 24 int prim_address, 25 RectWithSize local_rect, 26 RectWithSize segment_rect, 27 ivec4 user_data, 28 mat4 transform, 29 PictureTask pic_task, 30 int brush_flags, 31 vec4 unused 32) { 33 ImageResource res = fetch_image_resource(user_data.x); 34 vec2 uv0 = res.uv_rect.p0; 35 vec2 uv1 = res.uv_rect.p1; 36 37 // PictureTask src_task = fetch_picture_task(user_data.x); 38 vec2 texture_size = vec2(textureSize(sColor0, 0).xy); 39 vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size; 40 f = get_image_quad_uv(user_data.x, f); 41 vec2 uv = mix(uv0, uv1, f); 42 float perspective_interpolate = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0 ? 1.0 : 0.0; 43 44 vUv = uv / texture_size * mix(vi.world_pos.w, 1.0, perspective_interpolate); 45 vLayerAndPerspective = vec2(res.layer, perspective_interpolate); 46 vUvClipBounds = vec4(uv0, uv1) / texture_size.xyxy; 47 48 float lumR = 0.2126; 49 float lumG = 0.7152; 50 float lumB = 0.0722; 51 float oneMinusLumR = 1.0 - lumR; 52 float oneMinusLumG = 1.0 - lumG; 53 float oneMinusLumB = 1.0 - lumB; 54 55 float amount = float(user_data.z) / 65536.0; 56 float invAmount = 1.0 - amount; 57 58 vOp = user_data.y; 59 vAmount = amount; 60 61 switch (vOp) { 62 case 2: { 63 // Grayscale 64 vColorMat = mat3( 65 vec3(lumR + oneMinusLumR * invAmount, lumR - lumR * invAmount, lumR - lumR * invAmount), 66 vec3(lumG - lumG * invAmount, lumG + oneMinusLumG * invAmount, lumG - lumG * invAmount), 67 vec3(lumB - lumB * invAmount, lumB - lumB * invAmount, lumB + oneMinusLumB * invAmount) 68 ); 69 vColorOffset = vec3(0.0); 70 break; 71 } 72 case 3: { 73 // HueRotate 74 float c = cos(amount); 75 float s = sin(amount); 76 vColorMat = mat3( 77 vec3(lumR + oneMinusLumR * c - lumR * s, lumR - lumR * c + 0.143 * s, lumR - lumR * c - oneMinusLumR * s), 78 vec3(lumG - lumG * c - lumG * s, lumG + oneMinusLumG * c + 0.140 * s, lumG - lumG * c + lumG * s), 79 vec3(lumB - lumB * c + oneMinusLumB * s, lumB - lumB * c - 0.283 * s, lumB + oneMinusLumB * c + lumB * s) 80 ); 81 vColorOffset = vec3(0.0); 82 break; 83 } 84 case 5: { 85 // Saturate 86 vColorMat = mat3( 87 vec3(invAmount * lumR + amount, invAmount * lumR, invAmount * lumR), 88 vec3(invAmount * lumG, invAmount * lumG + amount, invAmount * lumG), 89 vec3(invAmount * lumB, invAmount * lumB, invAmount * lumB + amount) 90 ); 91 vColorOffset = vec3(0.0); 92 break; 93 } 94 case 6: { 95 // Sepia 96 vColorMat = mat3( 97 vec3(0.393 + 0.607 * invAmount, 0.349 - 0.349 * invAmount, 0.272 - 0.272 * invAmount), 98 vec3(0.769 - 0.769 * invAmount, 0.686 + 0.314 * invAmount, 0.534 - 0.534 * invAmount), 99 vec3(0.189 - 0.189 * invAmount, 0.168 - 0.168 * invAmount, 0.131 + 0.869 * invAmount) 100 ); 101 vColorOffset = vec3(0.0); 102 break; 103 } 104 case 10: { 105 // Color Matrix 106 vec4 mat_data[3] = fetch_from_gpu_cache_3(user_data.z); 107 vec4 offset_data = fetch_from_gpu_cache_1(user_data.z + 4); 108 vColorMat = mat3(mat_data[0].xyz, mat_data[1].xyz, mat_data[2].xyz); 109 vColorOffset = offset_data.rgb; 110 break; 111 } 112 default: break; 113 } 114} 115#endif 116 117#ifdef WR_FRAGMENT_SHADER 118vec3 Contrast(vec3 Cs, float amount) { 119 return Cs.rgb * amount - 0.5 * amount + 0.5; 120} 121 122vec3 Invert(vec3 Cs, float amount) { 123 return mix(Cs.rgb, vec3(1.0) - Cs.rgb, amount); 124} 125 126vec3 Brightness(vec3 Cs, float amount) { 127 // Apply the brightness factor. 128 // Resulting color needs to be clamped to output range 129 // since we are pre-multiplying alpha in the shader. 130 return clamp(Cs.rgb * amount, vec3(0.0), vec3(1.0)); 131} 132 133// Based on the Gecko's implementation in 134// https://hg.mozilla.org/mozilla-central/file/91b4c3687d75/gfx/src/FilterSupport.cpp#l24 135// These could be made faster by sampling a lookup table stored in a float texture 136// with linear interpolation. 137 138vec3 SrgbToLinear(vec3 color) { 139 vec3 c1 = color / 12.92; 140 vec3 c2 = pow(color / 1.055 + vec3(0.055 / 1.055), vec3(2.4)); 141 return if_then_else(lessThanEqual(color, vec3(0.04045)), c1, c2); 142} 143 144vec3 LinearToSrgb(vec3 color) { 145 vec3 c1 = color * 12.92; 146 vec3 c2 = vec3(1.055) * pow(color, vec3(1.0 / 2.4)) - vec3(0.055); 147 return if_then_else(lessThanEqual(color, vec3(0.0031308)), c1, c2); 148} 149 150Fragment brush_fs() { 151 float perspective_divisor = mix(gl_FragCoord.w, 1.0, vLayerAndPerspective.y); 152 vec2 uv = vUv * perspective_divisor; 153 vec4 Cs = texture(sColor0, vec3(uv, vLayerAndPerspective.x)); 154 155 // Un-premultiply the input. 156 float alpha = Cs.a; 157 vec3 color = alpha != 0.0 ? Cs.rgb / alpha : Cs.rgb; 158 159 switch (vOp) { 160 case 0: 161 break; 162 case 1: 163 color = Contrast(color, vAmount); 164 break; 165 case 4: 166 color = Invert(color, vAmount); 167 break; 168 case 7: 169 color = Brightness(color, vAmount); 170 break; 171 case 8: // Opacity 172 alpha *= vAmount; 173 break; 174 case 11: 175 color = SrgbToLinear(color); 176 break; 177 case 12: 178 color = LinearToSrgb(color); 179 break; 180 default: 181 color = vColorMat * color + vColorOffset; 182 } 183 184 // Fail-safe to ensure that we don't sample outside the rendered 185 // portion of a blend source. 186 alpha *= point_inside_rect(uv, vUvClipBounds.xy, vUvClipBounds.zw); 187 188 // Pre-multiply the alpha into the output value. 189 return Fragment(alpha * vec4(color, 1.0)); 190} 191#endif 192