composite.glsl (9195B)
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 // Composite a picture cache tile into the framebuffer. 6 7 // This shader must remain compatible with ESSL 1, at least for the 8 // WR_FEATURE_TEXTURE_EXTERNAL_ESSL1 feature, so that it can be used to render 9 // video on GLES devices without GL_OES_EGL_image_external_essl3 support. 10 // This means we cannot use textureSize(), int inputs/outputs, etc. 11 12 #include shared 13 14 #ifdef WR_FEATURE_YUV 15 #include yuv 16 #endif 17 18 #ifndef WR_FEATURE_FAST_PATH 19 // Parameters for compositor clip 20 varying highp vec2 vNormalizedWorldPos; 21 flat varying highp vec2 vRoundedClipParams; 22 flat varying highp vec4 vRoundedClipRadii; 23 #endif 24 25 #ifdef WR_FEATURE_YUV 26 flat varying YUV_PRECISION vec3 vYcbcrBias; 27 flat varying YUV_PRECISION mat3 vRgbFromDebiasedYcbcr; 28 // YUV format. Packed in to vector to avoid bug 1630356. 29 flat varying mediump ivec2 vYuvFormat; 30 31 #ifdef SWGL_DRAW_SPAN 32 flat varying mediump int vRescaleFactor; 33 #endif 34 varying highp vec2 vUV_y; 35 varying highp vec2 vUV_u; 36 varying highp vec2 vUV_v; 37 flat varying highp vec4 vUVBounds_y; 38 flat varying highp vec4 vUVBounds_u; 39 flat varying highp vec4 vUVBounds_v; 40 #else 41 varying highp vec2 vUv; 42 #ifndef WR_FEATURE_FAST_PATH 43 flat varying mediump vec4 vColor; 44 flat varying highp vec4 vUVBounds; 45 #endif 46 #ifdef WR_FEATURE_TEXTURE_EXTERNAL_ESSL1 47 uniform mediump vec2 uTextureSize; 48 #endif 49 #endif 50 51 #ifdef WR_VERTEX_SHADER 52 // CPU side data is in CompositeInstance (gpu_types.rs) and is 53 // converted to GPU data using desc::COMPOSITE (renderer.rs) by 54 // filling vaos.composite_vao with VertexArrayKind::Composite. 55 PER_INSTANCE attribute vec4 aDeviceRect; 56 PER_INSTANCE attribute vec4 aDeviceClipRect; 57 PER_INSTANCE attribute vec4 aColor; 58 PER_INSTANCE attribute vec4 aParams; 59 PER_INSTANCE attribute vec2 aFlip; 60 61 #ifndef WR_FEATURE_FAST_PATH 62 PER_INSTANCE attribute vec4 aDeviceRoundedClipRect; 63 PER_INSTANCE attribute vec4 aDeviceRoundedClipRadii; 64 #endif 65 66 #ifdef WR_FEATURE_YUV 67 // YUV treats these as a UV clip rect (clamp) 68 PER_INSTANCE attribute vec4 aUvRect0; 69 PER_INSTANCE attribute vec4 aUvRect1; 70 PER_INSTANCE attribute vec4 aUvRect2; 71 #else 72 PER_INSTANCE attribute vec4 aUvRect0; 73 #endif 74 75 #ifdef WR_FEATURE_YUV 76 YuvPrimitive fetch_yuv_primitive() { 77 // From ExternalSurfaceDependency::Yuv: 78 int color_space = int(aParams.y); 79 int yuv_format = int(aParams.z); 80 int channel_bit_depth = int(aParams.w); 81 return YuvPrimitive(channel_bit_depth, color_space, yuv_format); 82 } 83 #endif 84 85 void main(void) { 86 // Flip device rect if required 87 vec4 device_rect = mix(aDeviceRect.xyzw, aDeviceRect.zwxy, aFlip.xyxy); 88 89 // Get world position 90 vec2 world_pos = mix(device_rect.xy, device_rect.zw, aPosition.xy); 91 92 // Clip the position to the world space clip rect 93 vec2 clipped_world_pos = clamp(world_pos, aDeviceClipRect.xy, aDeviceClipRect.zw); 94 95 #ifndef WR_FEATURE_FAST_PATH 96 vec2 half_clip_box_size = 0.5 * (aDeviceRoundedClipRect.zw - aDeviceRoundedClipRect.xy); 97 vNormalizedWorldPos = aDeviceRoundedClipRect.xy + half_clip_box_size - clipped_world_pos; 98 vRoundedClipParams = half_clip_box_size; 99 vRoundedClipRadii = aDeviceRoundedClipRadii; 100 #endif 101 102 // Derive the normalized UV from the clipped vertex position 103 vec2 uv = (clipped_world_pos - device_rect.xy) / (device_rect.zw - device_rect.xy); 104 105 #ifdef WR_FEATURE_YUV 106 YuvPrimitive prim = fetch_yuv_primitive(); 107 108 #ifdef SWGL_DRAW_SPAN 109 // swgl_commitTextureLinearYUV needs to know the color space specifier and 110 // also needs to know how many bits of scaling are required to normalize 111 // HDR textures. Note that MSB HDR formats don't need renormalization. 112 vRescaleFactor = 0; 113 if (prim.channel_bit_depth > 8 && prim.yuv_format != YUV_FORMAT_P010) { 114 vRescaleFactor = 16 - prim.channel_bit_depth; 115 } 116 #endif 117 118 YuvColorMatrixInfo mat_info = get_rgb_from_ycbcr_info(prim); 119 vYcbcrBias = mat_info.ycbcr_bias; 120 vRgbFromDebiasedYcbcr = mat_info.rgb_from_debiased_ycbrc; 121 122 vYuvFormat.x = prim.yuv_format; 123 124 write_uv_rect( 125 aUvRect0.xy, 126 aUvRect0.zw, 127 uv, 128 TEX_SIZE_YUV(sColor0), 129 vUV_y, 130 vUVBounds_y 131 ); 132 write_uv_rect( 133 aUvRect1.xy, 134 aUvRect1.zw, 135 uv, 136 TEX_SIZE_YUV(sColor1), 137 vUV_u, 138 vUVBounds_u 139 ); 140 write_uv_rect( 141 aUvRect2.xy, 142 aUvRect2.zw, 143 uv, 144 TEX_SIZE_YUV(sColor2), 145 vUV_v, 146 vUVBounds_v 147 ); 148 #else 149 uv = mix(aUvRect0.xy, aUvRect0.zw, uv); 150 // The uvs may be inverted, so use the min and max for the bounds 151 vec4 uvBounds = vec4(min(aUvRect0.xy, aUvRect0.zw), max(aUvRect0.xy, aUvRect0.zw)); 152 if (int(aParams.y) == UV_TYPE_UNNORMALIZED) { 153 // using an atlas, so UVs are in pixels, and need to be 154 // normalized and clamped. 155 #if defined(WR_FEATURE_TEXTURE_RECT) 156 vec2 texture_size = vec2(1.0, 1.0); 157 #elif defined(WR_FEATURE_TEXTURE_EXTERNAL_ESSL1) 158 vec2 texture_size = uTextureSize; 159 #else 160 vec2 texture_size = vec2(TEX_SIZE(sColor0)); 161 #endif 162 uvBounds += vec4(0.5, 0.5, -0.5, -0.5); 163 #ifndef WR_FEATURE_TEXTURE_RECT 164 uv /= texture_size; 165 uvBounds /= texture_size.xyxy; 166 #endif 167 } 168 169 vUv = uv; 170 #ifndef WR_FEATURE_FAST_PATH 171 vUVBounds = uvBounds; 172 // Pass through color 173 vColor = aColor; 174 #endif 175 #endif 176 177 gl_Position = uTransform * vec4(clipped_world_pos, 0.0, 1.0); 178 } 179 #endif 180 181 #ifdef WR_FRAGMENT_SHADER 182 183 #ifndef WR_FEATURE_FAST_PATH 184 // See https://www.shadertoy.com/view/4llXD7 185 // Notes: 186 // * pos is centered in the origin (so 0,0 is the center of the box). 187 // * The border radii must not be larger than half_box_size. 188 float sd_round_box(in vec2 pos, in vec2 half_box_size, in vec4 radii) { 189 radii.xy = (pos.x > 0.0) ? radii.xy : radii.zw; 190 radii.x = (pos.y > 0.0) ? radii.x : radii.y; 191 vec2 q = abs(pos) - half_box_size + radii.x; 192 return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - radii.x; 193 } 194 #endif 195 196 void main(void) { 197 #ifdef WR_FEATURE_YUV 198 vec4 color = sample_yuv( 199 vYuvFormat.x, 200 vYcbcrBias, 201 vRgbFromDebiasedYcbcr, 202 vUV_y, 203 vUV_u, 204 vUV_v, 205 vUVBounds_y, 206 vUVBounds_u, 207 vUVBounds_v 208 ); 209 #else 210 // The color is just the texture sample modulated by a supplied color. 211 // In the fast path we avoid clamping the UV coordinates and modulating by the color. 212 #ifdef WR_FEATURE_FAST_PATH 213 vec2 uv = vUv; 214 #else 215 vec2 uv = clamp(vUv, vUVBounds.xy, vUVBounds.zw); 216 #endif 217 vec4 texel = TEX_SAMPLE(sColor0, uv); 218 #ifdef WR_FEATURE_FAST_PATH 219 vec4 color = texel; 220 #else 221 vec4 color = vColor * texel; 222 #endif 223 #endif 224 225 // TODO(gw): Do we need to support this on ESSL1? 226 #ifndef WR_FEATURE_TEXTURE_EXTERNAL_ESSL1 227 #ifndef WR_FEATURE_FAST_PATH 228 // Apply compositor clip 229 float aa_range = compute_aa_range(vNormalizedWorldPos); 230 231 float dist = sd_round_box( 232 vNormalizedWorldPos, 233 vRoundedClipParams, 234 vRoundedClipRadii 235 ); 236 237 // Compute AA for the given dist and range. 238 float clip_alpha = distance_aa(aa_range, dist); 239 240 // Apply clip alpha 241 color *= clip_alpha; 242 #endif 243 #endif 244 245 write_output(color); 246 } 247 248 #ifdef SWGL_DRAW_SPAN 249 void swgl_drawSpanRGBA8() { 250 251 #ifndef WR_FEATURE_FAST_PATH 252 // If there is per-fragment clipping to do, we need to bail 253 // out of the span shader. 254 if (any(greaterThan(vRoundedClipRadii, vec4(0.0)))) { 255 return; 256 } 257 #endif // WR_FEATURE_FAST_PATH 258 259 #ifdef WR_FEATURE_YUV 260 if (vYuvFormat.x == YUV_FORMAT_PLANAR) { 261 swgl_commitTextureLinearYUV(sColor0, vUV_y, vUVBounds_y, 262 sColor1, vUV_u, vUVBounds_u, 263 sColor2, vUV_v, vUVBounds_v, 264 vYcbcrBias, 265 vRgbFromDebiasedYcbcr, 266 vRescaleFactor); 267 } else if (vYuvFormat.x == YUV_FORMAT_NV12 || vYuvFormat.x == YUV_FORMAT_P010) { 268 swgl_commitTextureLinearYUV(sColor0, vUV_y, vUVBounds_y, 269 sColor1, vUV_u, vUVBounds_u, 270 vYcbcrBias, 271 vRgbFromDebiasedYcbcr, 272 vRescaleFactor); 273 } else if (vYuvFormat.x == YUV_FORMAT_INTERLEAVED) { 274 swgl_commitTextureLinearYUV(sColor0, vUV_y, vUVBounds_y, 275 vYcbcrBias, 276 vRgbFromDebiasedYcbcr, 277 vRescaleFactor); 278 } 279 #else 280 #ifdef WR_FEATURE_FAST_PATH 281 vec4 color = vec4(1.0); 282 #ifdef WR_FEATURE_TEXTURE_RECT 283 vec4 uvBounds = vec4(vec2(0.0), vec2(textureSize(sColor0))); 284 #else 285 vec4 uvBounds = vec4(0.0, 0.0, 1.0, 1.0); 286 #endif 287 #else 288 vec4 color = vColor; 289 vec4 uvBounds = vUVBounds; 290 #endif 291 292 if (color != vec4(1.0)) { 293 swgl_commitTextureColorRGBA8(sColor0, vUv, uvBounds, color); 294 } else { 295 swgl_commitTextureRGBA8(sColor0, vUv, uvBounds); 296 } 297 #endif 298 } 299 #endif // SWGL_DRAW_SPAN 300 301 #endif