1 // Copyright 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/viz/service/display/shader.h"
6 
7 #include <stddef.h>
8 
9 #include <algorithm>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/logging.h"
14 #include "base/strings/char_traits.h"
15 #include "base/strings/strcat.h"
16 #include "base/strings/stringprintf.h"
17 #include "components/viz/service/display/static_geometry_binding.h"
18 #include "gpu/command_buffer/client/gles2_interface.h"
19 #include "ui/gfx/color_transform.h"
20 #include "ui/gfx/geometry/point.h"
21 #include "ui/gfx/geometry/size.h"
22 
StripLambda(base::StringPiece shader)23 constexpr base::StringPiece StripLambda(base::StringPiece shader) {
24   // Must contain at least "[]() {}".
25   DCHECK(shader.starts_with("[]() {"));
26   DCHECK(shader.ends_with("}"));
27   shader.remove_prefix(6);
28   shader.remove_suffix(1);
29   return shader;
30 }
31 
32 // Shaders are passed in with lambda syntax, which tricks clang-format into
33 // handling them correctly. StripLambda removes this.
34 #define SHADER0(Src) StripLambda(#Src)
35 
36 #define HDR(x)        \
37   do {                \
38     header += x "\n"; \
39   } while (0)
40 #define SRC(x)             \
41   do {                     \
42     source += "  " x "\n"; \
43   } while (0)
44 
45 using gpu::gles2::GLES2Interface;
46 
47 namespace viz {
48 
49 namespace {
50 
GetProgramUniformLocations(GLES2Interface * context,unsigned program,size_t count,const char ** uniforms,int * locations,int * base_uniform_index)51 static void GetProgramUniformLocations(GLES2Interface* context,
52                                        unsigned program,
53                                        size_t count,
54                                        const char** uniforms,
55                                        int* locations,
56                                        int* base_uniform_index) {
57   for (size_t i = 0; i < count; i++) {
58     locations[i] = (*base_uniform_index)++;
59     context->BindUniformLocationCHROMIUM(program, locations[i], uniforms[i]);
60   }
61 }
62 
SetFragmentTexCoordPrecision(TexCoordPrecision requested_precision,std::string * shader_string)63 static void SetFragmentTexCoordPrecision(TexCoordPrecision requested_precision,
64                                          std::string* shader_string) {
65   const char* prefix = "";
66   switch (requested_precision) {
67     case TEX_COORD_PRECISION_HIGH:
68       DCHECK_NE(shader_string->find("TexCoordPrecision"), std::string::npos);
69       prefix =
70           "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
71           "  #define TexCoordPrecision highp\n"
72           "#else\n"
73           "  #define TexCoordPrecision mediump\n"
74           "#endif\n";
75       break;
76     case TEX_COORD_PRECISION_MEDIUM:
77       DCHECK_NE(shader_string->find("TexCoordPrecision"), std::string::npos);
78       prefix = "#define TexCoordPrecision mediump\n";
79       break;
80     case TEX_COORD_PRECISION_NA:
81       DCHECK_EQ(shader_string->find("TexCoordPrecision"), std::string::npos);
82       DCHECK_EQ(shader_string->find("texture2D"), std::string::npos);
83       DCHECK_EQ(shader_string->find("texture2DRect"), std::string::npos);
84       break;
85     default:
86       NOTREACHED();
87       break;
88   }
89   const char* lut_prefix = "#define LutLookup texture2D\n";
90   shader_string->insert(0, prefix);
91   shader_string->insert(0, lut_prefix);
92 }
93 
TexCoordPrecisionRequired(GLES2Interface * context,int * highp_threshold_cache,int highp_threshold_min,int x,int y)94 TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
95                                             int* highp_threshold_cache,
96                                             int highp_threshold_min,
97                                             int x,
98                                             int y) {
99   if (*highp_threshold_cache == 0) {
100     // Initialize range and precision with minimum spec values for when
101     // GetShaderPrecisionFormat is a test stub.
102     // TODO(brianderson): Implement better stubs of GetShaderPrecisionFormat
103     // everywhere.
104     GLint range[2] = {14, 14};
105     GLint precision = 10;
106     context->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT,
107                                       range, &precision);
108     *highp_threshold_cache = 1 << precision;
109   }
110 
111   int highp_threshold = std::max(*highp_threshold_cache, highp_threshold_min);
112   if (x > highp_threshold || y > highp_threshold)
113     return TEX_COORD_PRECISION_HIGH;
114   return TEX_COORD_PRECISION_MEDIUM;
115 }
116 
SetFragmentSamplerType(SamplerType requested_type,std::string * shader_string)117 void SetFragmentSamplerType(SamplerType requested_type,
118                             std::string* shader_string) {
119   const char* prefix = nullptr;
120   switch (requested_type) {
121     case SAMPLER_TYPE_2D:
122       DCHECK_NE(shader_string->find("SamplerType"), std::string::npos);
123       DCHECK_NE(shader_string->find("TextureLookup"), std::string::npos);
124       prefix =
125           "#define SamplerType sampler2D\n"
126           "#define TextureLookup texture2D\n";
127       break;
128     case SAMPLER_TYPE_2D_RECT:
129       DCHECK_NE(shader_string->find("SamplerType"), std::string::npos);
130       DCHECK_NE(shader_string->find("TextureLookup"), std::string::npos);
131       prefix =
132           "#extension GL_ARB_texture_rectangle : require\n"
133           "#define SamplerType sampler2DRect\n"
134           "#define TextureLookup texture2DRect\n";
135       break;
136     case SAMPLER_TYPE_EXTERNAL_OES:
137       DCHECK_NE(shader_string->find("SamplerType"), std::string::npos);
138       DCHECK_NE(shader_string->find("TextureLookup"), std::string::npos);
139       prefix =
140           "#extension GL_OES_EGL_image_external : enable\n"
141           "#extension GL_NV_EGL_stream_consumer_external : enable\n"
142           "#define SamplerType samplerExternalOES\n"
143           "#define TextureLookup texture2D\n";
144       break;
145     case SAMPLER_TYPE_NA:
146       DCHECK_EQ(shader_string->find("SamplerType"), std::string::npos);
147       DCHECK_EQ(shader_string->find("TextureLookup"), std::string::npos);
148       return;
149     default:
150       NOTREACHED();
151       return;
152   }
153   shader_string->insert(0, prefix);
154 }
155 
156 }  // namespace
157 
TexCoordPrecisionRequired(GLES2Interface * context,int * highp_threshold_cache,int highp_threshold_min,const gfx::Point & max_coordinate)158 TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
159                                             int* highp_threshold_cache,
160                                             int highp_threshold_min,
161                                             const gfx::Point& max_coordinate) {
162   return TexCoordPrecisionRequired(context, highp_threshold_cache,
163                                    highp_threshold_min, max_coordinate.x(),
164                                    max_coordinate.y());
165 }
166 
TexCoordPrecisionRequired(GLES2Interface * context,int * highp_threshold_cache,int highp_threshold_min,const gfx::Size & max_size)167 TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
168                                             int* highp_threshold_cache,
169                                             int highp_threshold_min,
170                                             const gfx::Size& max_size) {
171   return TexCoordPrecisionRequired(context, highp_threshold_cache,
172                                    highp_threshold_min, max_size.width(),
173                                    max_size.height());
174 }
175 
VertexShader()176 VertexShader::VertexShader() {}
177 
Init(GLES2Interface * context,unsigned program,int * base_uniform_index)178 void VertexShader::Init(GLES2Interface* context,
179                         unsigned program,
180                         int* base_uniform_index) {
181   std::vector<const char*> uniforms;
182   std::vector<int> locations;
183 
184   switch (tex_coord_transform_) {
185     case TEX_COORD_TRANSFORM_NONE:
186       break;
187     case TEX_COORD_TRANSFORM_VEC4:
188     case TEX_COORD_TRANSFORM_TRANSLATED_VEC4:
189       uniforms.push_back("vertexTexTransform");
190       break;
191     case TEX_COORD_TRANSFORM_MATRIX:
192       uniforms.push_back("texMatrix");
193       break;
194   }
195   if (is_ya_uv_) {
196     uniforms.push_back("yaTexScale");
197     uniforms.push_back("yaTexOffset");
198     uniforms.push_back("uvTexScale");
199     uniforms.push_back("uvTexOffset");
200   }
201   uniforms.push_back("matrix");
202   if (has_vertex_opacity_)
203     uniforms.push_back("opacity");
204   if (aa_mode_ == USE_AA) {
205     uniforms.push_back("viewport");
206     uniforms.push_back("edge");
207   }
208   if (position_source_ == POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM)
209     uniforms.push_back("quad");
210 
211   locations.resize(uniforms.size());
212 
213   GetProgramUniformLocations(context, program, uniforms.size(), uniforms.data(),
214                              locations.data(), base_uniform_index);
215 
216   size_t index = 0;
217   switch (tex_coord_transform_) {
218     case TEX_COORD_TRANSFORM_NONE:
219       break;
220     case TEX_COORD_TRANSFORM_VEC4:
221     case TEX_COORD_TRANSFORM_TRANSLATED_VEC4:
222       vertex_tex_transform_location_ = locations[index++];
223       break;
224     case TEX_COORD_TRANSFORM_MATRIX:
225       tex_matrix_location_ = locations[index++];
226       break;
227   }
228   if (is_ya_uv_) {
229     ya_tex_scale_location_ = locations[index++];
230     ya_tex_offset_location_ = locations[index++];
231     uv_tex_scale_location_ = locations[index++];
232     uv_tex_offset_location_ = locations[index++];
233   }
234   matrix_location_ = locations[index++];
235   if (has_vertex_opacity_)
236     vertex_opacity_location_ = locations[index++];
237   if (aa_mode_ == USE_AA) {
238     viewport_location_ = locations[index++];
239     edge_location_ = locations[index++];
240   }
241   if (position_source_ == POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM)
242     quad_location_ = locations[index++];
243 }
244 
GetShaderString() const245 std::string VertexShader::GetShaderString() const {
246   // We unconditionally use highp in the vertex shader since
247   // we are unlikely to be vertex shader bound when drawing large quads.
248   // Also, some vertex shaders mutate the texture coordinate in such a
249   // way that the effective precision might be lower than expected.
250   std::string header = "#define TexCoordPrecision highp\n";
251   std::string source = "void main() {\n";
252 
253   // Define the size of quads for attribute indexed uniform arrays.
254   if (use_uniform_arrays_) {
255     header += base::StringPrintf("#define NUM_QUADS %d\n",
256                                  StaticGeometryBinding::NUM_QUADS);
257   }
258 
259   // Read the index variables.
260   if (use_uniform_arrays_ || has_vertex_opacity_ ||
261       position_source_ == POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM) {
262     HDR("attribute float a_index;");
263     SRC("// Compute indices for uniform arrays.");
264     SRC("int vertex_index = int(a_index);");
265     if (use_uniform_arrays_)
266       SRC("int quad_index = int(a_index * 0.25);");
267     SRC("");
268   }
269 
270   // Read the position and compute gl_Position.
271   HDR("attribute TexCoordPrecision vec4 a_position;");
272   SRC("// Compute the position.");
273   switch (position_source_) {
274     case POSITION_SOURCE_ATTRIBUTE:
275       SRC("vec4 pos = a_position;");
276       break;
277     case POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM:
278       HDR("uniform TexCoordPrecision vec2 quad[4];");
279       SRC("vec4 pos = vec4(quad[vertex_index], a_position.z, a_position.w);");
280       break;
281   }
282     if (use_uniform_arrays_) {
283       HDR("uniform mat4 matrix[NUM_QUADS];");
284       SRC("gl_Position = matrix[quad_index] * pos;");
285     } else {
286       HDR("uniform mat4 matrix;");
287       SRC("gl_Position = matrix * pos;");
288     }
289 
290   // Compute the anti-aliasing edge distances.
291   if (aa_mode_ == USE_AA) {
292     HDR("uniform TexCoordPrecision vec3 edge[8];");
293     HDR("uniform vec4 viewport;");
294     HDR("varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.");
295     SRC("// Compute anti-aliasing properties.\n");
296     SRC("vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);");
297     SRC("vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);");
298     SRC("edge_dist[0] = vec4(dot(edge[0], screen_pos),");
299     SRC("                    dot(edge[1], screen_pos),");
300     SRC("                    dot(edge[2], screen_pos),");
301     SRC("                    dot(edge[3], screen_pos)) * gl_Position.w;");
302     SRC("edge_dist[1] = vec4(dot(edge[4], screen_pos),");
303     SRC("                    dot(edge[5], screen_pos),");
304     SRC("                    dot(edge[6], screen_pos),");
305     SRC("                    dot(edge[7], screen_pos)) * gl_Position.w;");
306   }
307 
308   // Read, transform, and write texture coordinates.
309   if (tex_coord_source_ != TEX_COORD_SOURCE_NONE) {
310     if (is_ya_uv_) {
311       HDR("varying TexCoordPrecision vec2 v_uvTexCoord;");
312       HDR("varying TexCoordPrecision vec2 v_yaTexCoord;");
313     } else {
314       HDR("varying TexCoordPrecision vec2 v_texCoord;");
315     }
316 
317     SRC("// Compute texture coordinates.");
318     // Read coordinates.
319     switch (tex_coord_source_) {
320       case TEX_COORD_SOURCE_NONE:
321         break;
322       case TEX_COORD_SOURCE_POSITION:
323         SRC("vec2 texCoord = pos.xy;");
324         break;
325       case TEX_COORD_SOURCE_ATTRIBUTE:
326         HDR("attribute TexCoordPrecision vec2 a_texCoord;");
327         SRC("vec2 texCoord = a_texCoord;");
328         break;
329     }
330     // Transform coordinates (except YUV).
331     switch (tex_coord_transform_) {
332       case TEX_COORD_TRANSFORM_NONE:
333         break;
334       case TEX_COORD_TRANSFORM_TRANSLATED_VEC4:
335         SRC("texCoord = texCoord + vec2(0.5);");
336         FALLTHROUGH;
337       case TEX_COORD_TRANSFORM_VEC4:
338         if (use_uniform_arrays_) {
339           HDR("uniform TexCoordPrecision vec4 vertexTexTransform[NUM_QUADS];");
340           SRC("TexCoordPrecision vec4 texTrans =");
341           SRC("    vertexTexTransform[quad_index];");
342           SRC("texCoord = texCoord * texTrans.zw + texTrans.xy;");
343         } else {
344           HDR("uniform TexCoordPrecision vec4 vertexTexTransform;");
345           SRC("texCoord = texCoord * vertexTexTransform.zw +");
346           SRC("           vertexTexTransform.xy;");
347         }
348         break;
349       case TEX_COORD_TRANSFORM_MATRIX:
350         HDR("uniform TexCoordPrecision mat4 texMatrix;");
351         SRC("texCoord = (texMatrix * vec4(texCoord.xy, 0.0, 1.0)).xy;");
352         break;
353     }
354     // Write the output texture coordinates.
355     if (is_ya_uv_) {
356       HDR("uniform TexCoordPrecision vec2 uvTexOffset;");
357       HDR("uniform TexCoordPrecision vec2 uvTexScale;");
358       HDR("uniform TexCoordPrecision vec2 yaTexOffset;");
359       HDR("uniform TexCoordPrecision vec2 yaTexScale;");
360       SRC("v_yaTexCoord = texCoord * yaTexScale + yaTexOffset;");
361       SRC("v_uvTexCoord = texCoord * uvTexScale + uvTexOffset;");
362     } else {
363       SRC("v_texCoord = texCoord;");
364     }
365   }
366 
367   // Write varying vertex opacity.
368   if (has_vertex_opacity_) {
369     HDR("varying float v_alpha;");
370     if (use_uniform_arrays_) {
371       HDR("uniform float opacity[NUM_QUADS * 4];");
372     } else {
373       HDR("uniform float opacity[4];");
374     }
375     SRC("v_alpha = opacity[vertex_index];");
376   }
377 
378   // Add cargo-culted dummy variables for Android.
379   if (has_dummy_variables_) {
380     HDR("uniform TexCoordPrecision vec2 dummy_uniform;");
381     HDR("varying TexCoordPrecision vec2 dummy_varying;");
382     SRC("dummy_varying = dummy_uniform;");
383   }
384 
385   source += "}\n";
386   return header + source;
387 }
388 
FragmentShader()389 FragmentShader::FragmentShader() {}
390 
GetShaderString() const391 std::string FragmentShader::GetShaderString() const {
392   TexCoordPrecision precision = tex_coord_precision_;
393   // The AA shader values will use TexCoordPrecision.
394   if (aa_mode_ == USE_AA && precision == TEX_COORD_PRECISION_NA)
395     precision = TEX_COORD_PRECISION_MEDIUM;
396   std::string shader = GetShaderSource();
397   SetBlendModeFunctions(&shader);
398   SetRoundedCornerFunctions(&shader);
399   SetFragmentSamplerType(sampler_type_, &shader);
400   SetFragmentTexCoordPrecision(precision, &shader);
401   return shader;
402 }
403 
Init(GLES2Interface * context,unsigned program,int * base_uniform_index)404 void FragmentShader::Init(GLES2Interface* context,
405                           unsigned program,
406                           int* base_uniform_index) {
407   std::vector<const char*> uniforms;
408   std::vector<int> locations;
409   if (has_blend_mode()) {
410     uniforms.push_back("s_backdropTexture");
411     uniforms.push_back("s_originalBackdropTexture");
412     uniforms.push_back("backdropRect");
413   }
414   if (mask_mode_ != NO_MASK) {
415     uniforms.push_back("s_mask");
416     uniforms.push_back("maskTexCoordScale");
417     uniforms.push_back("maskTexCoordOffset");
418   }
419   if (has_color_matrix_) {
420     uniforms.push_back("colorMatrix");
421     uniforms.push_back("colorOffset");
422   }
423   if (has_uniform_alpha_)
424     uniforms.push_back("alpha");
425   if (has_background_color_)
426     uniforms.push_back("background_color");
427   if (has_tex_clamp_rect_)
428     uniforms.push_back("tex_clamp_rect");
429   switch (input_color_type_) {
430     case INPUT_COLOR_SOURCE_RGBA_TEXTURE:
431       uniforms.push_back("s_texture");
432       if (has_rgba_fragment_tex_transform_)
433         uniforms.push_back("fragmentTexTransform");
434       break;
435     case INPUT_COLOR_SOURCE_YUV_TEXTURES:
436       uniforms.push_back("y_texture");
437       if (uv_texture_mode_ == UV_TEXTURE_MODE_UV)
438         uniforms.push_back("uv_texture");
439       if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) {
440         uniforms.push_back("u_texture");
441         uniforms.push_back("v_texture");
442       }
443       if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE)
444         uniforms.push_back("a_texture");
445       uniforms.push_back("ya_clamp_rect");
446       uniforms.push_back("uv_clamp_rect");
447       uniforms.push_back("resource_multiplier");
448       uniforms.push_back("resource_offset");
449       break;
450     case INPUT_COLOR_SOURCE_UNIFORM:
451       uniforms.push_back("color");
452       break;
453   }
454   if (has_output_color_matrix_)
455     uniforms.emplace_back("output_color_matrix");
456 
457   if (has_tint_color_matrix_)
458     uniforms.emplace_back("tint_color_matrix");
459 
460   if (has_rounded_corner_) {
461     uniforms.emplace_back("roundedCornerRect");
462     uniforms.emplace_back("roundedCornerRadius");
463   }
464 
465   locations.resize(uniforms.size());
466 
467   GetProgramUniformLocations(context, program, uniforms.size(), uniforms.data(),
468                              locations.data(), base_uniform_index);
469 
470   size_t index = 0;
471   if (has_blend_mode()) {
472     backdrop_location_ = locations[index++];
473     original_backdrop_location_ = locations[index++];
474     backdrop_rect_location_ = locations[index++];
475   }
476   if (mask_mode_ != NO_MASK) {
477     mask_sampler_location_ = locations[index++];
478     mask_tex_coord_scale_location_ = locations[index++];
479     mask_tex_coord_offset_location_ = locations[index++];
480   }
481   if (has_color_matrix_) {
482     color_matrix_location_ = locations[index++];
483     color_offset_location_ = locations[index++];
484   }
485   if (has_uniform_alpha_)
486     alpha_location_ = locations[index++];
487   if (has_background_color_)
488     background_color_location_ = locations[index++];
489   if (has_tex_clamp_rect_)
490     tex_clamp_rect_location_ = locations[index++];
491   switch (input_color_type_) {
492     case INPUT_COLOR_SOURCE_RGBA_TEXTURE:
493       sampler_location_ = locations[index++];
494       if (has_rgba_fragment_tex_transform_)
495         fragment_tex_transform_location_ = locations[index++];
496       break;
497     case INPUT_COLOR_SOURCE_YUV_TEXTURES:
498       y_texture_location_ = locations[index++];
499       if (uv_texture_mode_ == UV_TEXTURE_MODE_UV)
500         uv_texture_location_ = locations[index++];
501       if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) {
502         u_texture_location_ = locations[index++];
503         v_texture_location_ = locations[index++];
504       }
505       if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE)
506         a_texture_location_ = locations[index++];
507       ya_clamp_rect_location_ = locations[index++];
508       uv_clamp_rect_location_ = locations[index++];
509       resource_multiplier_location_ = locations[index++];
510       resource_offset_location_ = locations[index++];
511       break;
512     case INPUT_COLOR_SOURCE_UNIFORM:
513       color_location_ = locations[index++];
514       break;
515   }
516 
517   if (has_output_color_matrix_)
518     output_color_matrix_location_ = locations[index++];
519 
520   if (has_tint_color_matrix_)
521     tint_color_matrix_location_ = locations[index++];
522 
523   if (has_rounded_corner_) {
524     rounded_corner_rect_location_ = locations[index++];
525     rounded_corner_radius_location_ = locations[index++];
526   }
527 
528   DCHECK_EQ(index, locations.size());
529 }
530 
SetRoundedCornerFunctions(std::string * shader_string) const531 void FragmentShader::SetRoundedCornerFunctions(
532     std::string* shader_string) const {
533   if (!has_rounded_corner_)
534     return;
535 
536   static constexpr base::StringPiece kUniforms = SHADER0([]() {
537     uniform vec4 roundedCornerRect;
538     uniform vec4 roundedCornerRadius;
539   });
540 
541   static constexpr base::StringPiece kFunctionRcUtility = SHADER0([]() {
542     // Returns a vector of size 4. Each component of a vector is set to 1 or 0
543     // representing whether |rcCoord| is a part of the respective corner or
544     // not.
545     // The component ordering is:
546     //     [Top left, Top right, Bottom right, Bottom left]
547     vec4 IsCorner(vec2 rcCoord) {
548       // Top left corner
549       if (rcCoord.x < roundedCornerRadius.x &&
550           rcCoord.y < roundedCornerRadius.x) {
551         return vec4(1.0, 0.0, 0.0, 0.0);
552       }
553 
554       // Top right corner
555       if (rcCoord.x > roundedCornerRect.z - roundedCornerRadius.y &&
556           rcCoord.y < roundedCornerRadius.y) {
557         return vec4(0.0, 1.0, 0.0, 0.0);
558       }
559 
560       // Bottom right corner
561       if (rcCoord.x > roundedCornerRect.z - roundedCornerRadius.z &&
562           rcCoord.y > roundedCornerRect.w - roundedCornerRadius.z) {
563         return vec4(0.0, 0.0, 1.0, 0.0);
564       }
565 
566       // Bottom left corner
567       if (rcCoord.x < roundedCornerRadius.w &&
568           rcCoord.y > roundedCornerRect.w - roundedCornerRadius.w) {
569         return vec4(0.0, 0.0, 0.0, 1.0);
570       }
571       return vec4(0.0, 0.0, 0.0, 0.0);
572     }
573 
574     // Returns the center of the rounded corner. |corner| holds the info on
575     // which corner the center is requested for.
576     vec2 GetCenter(vec4 corner, float radius) {
577       if (corner.x == 1.0) {
578         // Top left corner
579         return vec2(radius, radius);
580       } else if (corner.y == 1.0) {
581         // Top right corner
582         return vec2(roundedCornerRect.z - radius, radius);
583       } else if (corner.z == 1.0) {
584         // Bottom right corner
585         return vec2(roundedCornerRect.z - radius, roundedCornerRect.w - radius);
586       } else {
587         // Bottom left corner
588         return vec2(radius, roundedCornerRect.w - radius);
589       }
590     }
591   });
592 
593   static constexpr base::StringPiece kFunctionApplyRoundedCorner =
594       SHADER0([]() {
595         vec4 ApplyRoundedCorner(vec4 src) {
596           vec2 rcCoord = gl_FragCoord.xy - roundedCornerRect.xy;
597 
598           vec4 isCorner = IsCorner(rcCoord);
599 
600           // Get the radius to use based on the corner this fragment lies in.
601           float r = dot(isCorner, roundedCornerRadius);
602 
603           // If the radius is 0, then there is no rounded corner here. We can do
604           // an early return.
605           if (r == 0.0)
606             return src;
607 
608           // Vector to the corner's center this fragment is in.
609           // Due to precision errors on android, this variable requires a highp.
610           // See https://crbug.com/1009322
611           RoundedCornerPrecision vec2 cornerCenter = GetCenter(isCorner, r);
612 
613           // Vector from the center of the corner to the current fragment center
614           vec2 cxy = rcCoord - cornerCenter;
615 
616           // Compute the distance of the fragment's center from the corner's
617           // center.
618           float fragDst = length(cxy);
619 
620           float alpha = smoothstep(r - 1.0, r + 1.0, fragDst);
621           return vec4(0.0) * alpha + src * (1.0 - alpha);
622         }
623       });
624 
625   std::string shader;
626   shader.reserve(shader_string->size() + 2048);
627   shader += "precision mediump float;";
628   shader +=
629       "\n#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
630       "  #define RoundedCornerPrecision highp\n"
631       "#else\n"
632       "  #define RoundedCornerPrecision mediump\n"
633       "#endif\n";
634   base::StrAppend(&shader, {kUniforms, kFunctionRcUtility,
635                             kFunctionApplyRoundedCorner, *shader_string});
636   *shader_string = std::move(shader);
637 }
638 
SetBlendModeFunctions(std::string * shader_string) const639 void FragmentShader::SetBlendModeFunctions(std::string* shader_string) const {
640   if (!has_blend_mode()) {
641     return;
642   }
643 
644   static constexpr base::StringPiece kUniforms = SHADER0([]() {
645     uniform sampler2D s_backdropTexture;
646     uniform sampler2D s_originalBackdropTexture;
647     uniform TexCoordPrecision vec4 backdropRect;
648   });
649 
650   base::StringPiece function_apply_blend_mode;
651   if (mask_for_background_) {
652     static constexpr base::StringPiece kFunctionApplyBlendMode = SHADER0([]() {
653       vec4 ApplyBlendMode(vec4 src, float mask) {
654         TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
655         bgTexCoord *= backdropRect.zw;
656         vec4 backdrop = texture2D(s_backdropTexture, bgTexCoord);
657         vec4 original_backdrop =
658             texture2D(s_originalBackdropTexture, bgTexCoord);
659         vec4 dst = mix(original_backdrop, backdrop, mask);
660         return Blend(src, dst);
661       }
662     });
663     function_apply_blend_mode = kFunctionApplyBlendMode;
664   } else {
665     static constexpr base::StringPiece kFunctionApplyBlendMode = SHADER0([]() {
666       vec4 ApplyBlendMode(vec4 src) {
667         TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
668         bgTexCoord *= backdropRect.zw;
669         vec4 dst = texture2D(s_backdropTexture, bgTexCoord);
670         return Blend(src, dst);
671       }
672     });
673     function_apply_blend_mode = kFunctionApplyBlendMode;
674   }
675 
676   std::string shader;
677   shader.reserve(shader_string->size() + 1024);
678   shader += "precision mediump float;";
679   AppendHelperFunctions(&shader);
680   AppendBlendFunction(&shader);
681   base::StrAppend(&shader,
682                   {kUniforms, function_apply_blend_mode, *shader_string});
683   *shader_string = std::move(shader);
684 }
685 
AppendHelperFunctions(std::string * buffer) const686 void FragmentShader::AppendHelperFunctions(std::string* buffer) const {
687   static constexpr base::StringPiece kFunctionHardLight = SHADER0([]() {
688     vec3 hardLight(vec4 src, vec4 dst) {
689       vec3 result;
690       result.r =
691           (2.0 * src.r <= src.a)
692               ? (2.0 * src.r * dst.r)
693               : (src.a * dst.a - 2.0 * (dst.a - dst.r) * (src.a - src.r));
694       result.g =
695           (2.0 * src.g <= src.a)
696               ? (2.0 * src.g * dst.g)
697               : (src.a * dst.a - 2.0 * (dst.a - dst.g) * (src.a - src.g));
698       result.b =
699           (2.0 * src.b <= src.a)
700               ? (2.0 * src.b * dst.b)
701               : (src.a * dst.a - 2.0 * (dst.a - dst.b) * (src.a - src.b));
702       result.rgb += src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
703       return result;
704     }
705   });
706 
707   static constexpr base::StringPiece kFunctionColorDodgeComponent =
708       SHADER0([]() {
709         float getColorDodgeComponent(float srcc, float srca, float dstc,
710                                      float dsta) {
711           if (0.0 == dstc)
712             return srcc * (1.0 - dsta);
713           float d = srca - srcc;
714           if (0.0 == d)
715             return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
716           d = min(dsta, dstc * srca / d);
717           return d * srca + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
718         }
719       });
720 
721   static constexpr base::StringPiece kFunctionColorBurnComponent =
722       SHADER0([]() {
723         float getColorBurnComponent(float srcc, float srca, float dstc,
724                                     float dsta) {
725           if (dsta == dstc)
726             return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
727           if (0.0 == srcc)
728             return dstc * (1.0 - srca);
729           float d = max(0.0, dsta - (dsta - dstc) * srca / srcc);
730           return srca * d + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
731         }
732       });
733 
734   static constexpr base::StringPiece kFunctionSoftLightComponentPosDstAlpha =
735       SHADER0([]() {
736         float getSoftLightComponent(float srcc, float srca, float dstc,
737                                     float dsta) {
738           if (2.0 * srcc <= srca) {
739             return (dstc * dstc * (srca - 2.0 * srcc)) / dsta +
740                    (1.0 - dsta) * srcc + dstc * (-srca + 2.0 * srcc + 1.0);
741           } else if (4.0 * dstc <= dsta) {
742             float DSqd = dstc * dstc;
743             float DCub = DSqd * dstc;
744             float DaSqd = dsta * dsta;
745             float DaCub = DaSqd * dsta;
746             return (-DaCub * srcc +
747                     DaSqd * (srcc - dstc * (3.0 * srca - 6.0 * srcc - 1.0)) +
748                     12.0 * dsta * DSqd * (srca - 2.0 * srcc) -
749                     16.0 * DCub * (srca - 2.0 * srcc)) /
750                    DaSqd;
751           } else {
752             return -sqrt(dsta * dstc) * (srca - 2.0 * srcc) - dsta * srcc +
753                    dstc * (srca - 2.0 * srcc + 1.0) + srcc;
754           }
755         }
756       });
757 
758   static constexpr base::StringPiece kFunctionLum = SHADER0([]() {
759     float luminance(vec3 color) { return dot(vec3(0.3, 0.59, 0.11), color); }
760 
761     vec3 set_luminance(vec3 hueSat, float alpha, vec3 lumColor) {
762       float diff = luminance(lumColor - hueSat);
763       vec3 outColor = hueSat + diff;
764       float outLum = luminance(outColor);
765       float minComp = min(min(outColor.r, outColor.g), outColor.b);
766       float maxComp = max(max(outColor.r, outColor.g), outColor.b);
767       if (minComp < 0.0 && outLum != minComp) {
768         outColor =
769             outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /
770                          (outLum - minComp);
771       }
772       if (maxComp > alpha && maxComp != outLum) {
773         outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) *
774                              (alpha - outLum)) /
775                                 (maxComp - outLum);
776       }
777       return outColor;
778     }
779   });
780 
781   static constexpr base::StringPiece kFunctionSat = SHADER0([]() {
782     float saturation(vec3 color) {
783       return max(max(color.r, color.g), color.b) -
784              min(min(color.r, color.g), color.b);
785     }
786 
787     vec3 set_saturation_helper(float minComp, float midComp, float maxComp,
788                                float sat) {
789       if (minComp < maxComp) {
790         vec3 result;
791         result.r = 0.0;
792         result.g = sat * (midComp - minComp) / (maxComp - minComp);
793         result.b = sat;
794         return result;
795       } else {
796         return vec3(0, 0, 0);
797       }
798     }
799 
800     vec3 set_saturation(vec3 hueLumColor, vec3 satColor) {
801       float sat = saturation(satColor);
802       if (hueLumColor.r <= hueLumColor.g) {
803         if (hueLumColor.g <= hueLumColor.b) {
804           hueLumColor.rgb = set_saturation_helper(hueLumColor.r, hueLumColor.g,
805                                                   hueLumColor.b, sat);
806         } else if (hueLumColor.r <= hueLumColor.b) {
807           hueLumColor.rbg = set_saturation_helper(hueLumColor.r, hueLumColor.b,
808                                                   hueLumColor.g, sat);
809         } else {
810           hueLumColor.brg = set_saturation_helper(hueLumColor.b, hueLumColor.r,
811                                                   hueLumColor.g, sat);
812         }
813       } else if (hueLumColor.r <= hueLumColor.b) {
814         hueLumColor.grb = set_saturation_helper(hueLumColor.g, hueLumColor.r,
815                                                 hueLumColor.b, sat);
816       } else if (hueLumColor.g <= hueLumColor.b) {
817         hueLumColor.gbr = set_saturation_helper(hueLumColor.g, hueLumColor.b,
818                                                 hueLumColor.r, sat);
819       } else {
820         hueLumColor.bgr = set_saturation_helper(hueLumColor.b, hueLumColor.g,
821                                                 hueLumColor.r, sat);
822       }
823       return hueLumColor;
824     }
825   });
826 
827   switch (blend_mode_) {
828     case BLEND_MODE_OVERLAY:
829     case BLEND_MODE_HARD_LIGHT:
830       buffer->append(kFunctionHardLight.data(), kFunctionHardLight.size());
831       return;
832     case BLEND_MODE_COLOR_DODGE:
833       buffer->append(kFunctionColorDodgeComponent.data(),
834                      kFunctionColorDodgeComponent.size());
835       return;
836     case BLEND_MODE_COLOR_BURN:
837       buffer->append(kFunctionColorBurnComponent.data(),
838                      kFunctionColorBurnComponent.size());
839       return;
840     case BLEND_MODE_SOFT_LIGHT:
841       buffer->append(kFunctionSoftLightComponentPosDstAlpha.data(),
842                      kFunctionSoftLightComponentPosDstAlpha.size());
843       return;
844     case BLEND_MODE_HUE:
845     case BLEND_MODE_SATURATION:
846       base::StrAppend(buffer, {kFunctionLum, kFunctionSat});
847       return;
848     case BLEND_MODE_COLOR:
849     case BLEND_MODE_LUMINOSITY:
850       buffer->append(kFunctionLum.data(), kFunctionLum.size());
851       return;
852     default:
853       return;
854   }
855 }
856 
AppendBlendFunction(std::string * buffer) const857 void FragmentShader::AppendBlendFunction(std::string* buffer) const {
858   *buffer +=
859       "vec4 Blend(vec4 src, vec4 dst) {"
860       "    vec4 result;";
861   base::StrAppend(
862       buffer, {GetBlendFunctionBodyForAlpha(), GetBlendFunctionBodyForRGB()});
863   *buffer +=
864       "    return result;"
865       "}";
866 }
867 
GetBlendFunctionBodyForAlpha() const868 base::StringPiece FragmentShader::GetBlendFunctionBodyForAlpha() const {
869   if (blend_mode_ == BLEND_MODE_DESTINATION_IN)
870     return "result.a = src.a * dst.a;";
871   else
872     return "result.a = src.a + (1.0 - src.a) * dst.a;";
873 }
874 
GetBlendFunctionBodyForRGB() const875 base::StringPiece FragmentShader::GetBlendFunctionBodyForRGB() const {
876   switch (blend_mode_) {
877     case BLEND_MODE_NORMAL:
878       return "result.rgb = src.rgb + dst.rgb * (1.0 - src.a);";
879     case BLEND_MODE_DESTINATION_IN:
880       return "result.rgb = dst.rgb * src.a;";
881     case BLEND_MODE_SCREEN:
882       return "result.rgb = src.rgb + (1.0 - src.rgb) * dst.rgb;";
883     case BLEND_MODE_LIGHTEN:
884       return "result.rgb = max((1.0 - src.a) * dst.rgb + src.rgb,"
885              "                 (1.0 - dst.a) * src.rgb + dst.rgb);";
886     case BLEND_MODE_OVERLAY:
887       return "result.rgb = hardLight(dst, src);";
888     case BLEND_MODE_DARKEN:
889       return "result.rgb = min((1.0 - src.a) * dst.rgb + src.rgb,"
890              "                 (1.0 - dst.a) * src.rgb + dst.rgb);";
891     case BLEND_MODE_COLOR_DODGE:
892       return "result.r = getColorDodgeComponent(src.r, src.a, dst.r, dst.a);"
893              "result.g = getColorDodgeComponent(src.g, src.a, dst.g, dst.a);"
894              "result.b = getColorDodgeComponent(src.b, src.a, dst.b, dst.a);";
895     case BLEND_MODE_COLOR_BURN:
896       return "result.r = getColorBurnComponent(src.r, src.a, dst.r, dst.a);"
897              "result.g = getColorBurnComponent(src.g, src.a, dst.g, dst.a);"
898              "result.b = getColorBurnComponent(src.b, src.a, dst.b, dst.a);";
899     case BLEND_MODE_HARD_LIGHT:
900       return "result.rgb = hardLight(src, dst);";
901     case BLEND_MODE_SOFT_LIGHT:
902       return "if (0.0 == dst.a) {"
903              "  result.rgb = src.rgb;"
904              "} else {"
905              "  result.r = getSoftLightComponent(src.r, src.a, dst.r, dst.a);"
906              "  result.g = getSoftLightComponent(src.g, src.a, dst.g, dst.a);"
907              "  result.b = getSoftLightComponent(src.b, src.a, dst.b, dst.a);"
908              "}";
909     case BLEND_MODE_DIFFERENCE:
910       return "result.rgb = src.rgb + dst.rgb -"
911              "    2.0 * min(src.rgb * dst.a, dst.rgb * src.a);";
912     case BLEND_MODE_EXCLUSION:
913       return "result.rgb = dst.rgb + src.rgb - 2.0 * dst.rgb * src.rgb;";
914     case BLEND_MODE_MULTIPLY:
915       return "result.rgb = (1.0 - src.a) * dst.rgb +"
916              "    (1.0 - dst.a) * src.rgb + src.rgb * dst.rgb;";
917     case BLEND_MODE_HUE:
918       return "vec4 dstSrcAlpha = dst * src.a;"
919              "result.rgb ="
920              "    set_luminance(set_saturation(src.rgb * dst.a,"
921              "                                 dstSrcAlpha.rgb),"
922              "                  dstSrcAlpha.a,"
923              "                  dstSrcAlpha.rgb);"
924              "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
925     case BLEND_MODE_SATURATION:
926       return "vec4 dstSrcAlpha = dst * src.a;"
927              "result.rgb = set_luminance(set_saturation(dstSrcAlpha.rgb,"
928              "                                          src.rgb * dst.a),"
929              "                           dstSrcAlpha.a,"
930              "                           dstSrcAlpha.rgb);"
931              "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
932     case BLEND_MODE_COLOR:
933       return "vec4 srcDstAlpha = src * dst.a;"
934              "result.rgb = set_luminance(srcDstAlpha.rgb,"
935              "                           srcDstAlpha.a,"
936              "                           dst.rgb * src.a);"
937              "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
938     case BLEND_MODE_LUMINOSITY:
939       return "vec4 srcDstAlpha = src * dst.a;"
940              "result.rgb = set_luminance(dst.rgb * src.a,"
941              "                           srcDstAlpha.a,"
942              "                           srcDstAlpha.rgb);"
943              "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
944     case BLEND_MODE_NONE:
945       NOTREACHED();
946   }
947   return "result = vec4(1.0, 0.0, 0.0, 1.0);";
948 }
949 
GetShaderSource() const950 std::string FragmentShader::GetShaderSource() const {
951   std::string header = "precision mediump float;\n";
952   std::string source = "void main() {\n";
953 
954   // Read the input into vec4 texColor.
955   switch (input_color_type_) {
956     case INPUT_COLOR_SOURCE_RGBA_TEXTURE:
957       if (ignore_sampler_type_)
958         HDR("uniform sampler2D s_texture;");
959       else
960         HDR("uniform SamplerType s_texture;");
961       HDR("varying TexCoordPrecision vec2 v_texCoord;");
962       if (has_rgba_fragment_tex_transform_) {
963         HDR("uniform TexCoordPrecision vec4 fragmentTexTransform;");
964         SRC("// Transformed texture lookup");
965         SRC("TexCoordPrecision vec2 texCoord =");
966         SRC("    clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw +");
967         SRC("   fragmentTexTransform.xy;");
968         SRC("vec4 texColor = TextureLookup(s_texture, texCoord);");
969         DCHECK(!ignore_sampler_type_);
970         DCHECK(!has_tex_clamp_rect_);
971       } else {
972         SRC("// Texture lookup");
973         if (ignore_sampler_type_) {
974           SRC("vec4 texColor = texture2D(s_texture, v_texCoord);");
975           DCHECK(!has_tex_clamp_rect_);
976         } else {
977           SRC("TexCoordPrecision vec2 texCoord = v_texCoord;");
978           if (has_tex_clamp_rect_) {
979             HDR("uniform vec4 tex_clamp_rect;");
980             SRC("texCoord = max(tex_clamp_rect.xy,");
981             SRC("    min(tex_clamp_rect.zw, texCoord));");
982           }
983           SRC("vec4 texColor = TextureLookup(s_texture, texCoord);");
984         }
985       }
986       break;
987     case INPUT_COLOR_SOURCE_YUV_TEXTURES:
988       DCHECK(!has_tex_clamp_rect_);
989       // Compute the clamped texture coordinates for the YA and UV textures.
990       HDR("uniform SamplerType y_texture;");
991       SRC("// YUV texture lookup and conversion to RGB.");
992       SRC("vec2 ya_clamped =");
993       SRC("    max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));");
994       SRC("vec2 uv_clamped =");
995       SRC("    max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));");
996       // Read the Y and UV or U and V textures into |yuv|.
997       SRC("vec4 texColor;");
998       SRC("texColor.w = 1.0;");
999       SRC("texColor.x = TextureLookup(y_texture, ya_clamped).x;");
1000       if (uv_texture_mode_ == UV_TEXTURE_MODE_UV) {
1001         HDR("uniform SamplerType uv_texture;");
1002         SRC("texColor.yz = TextureLookup(uv_texture, uv_clamped).xy;");
1003       }
1004       if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) {
1005         HDR("uniform SamplerType u_texture;");
1006         HDR("uniform SamplerType v_texture;");
1007         SRC("texColor.y = TextureLookup(u_texture, uv_clamped).x;");
1008         SRC("texColor.z = TextureLookup(v_texture, uv_clamped).x;");
1009       }
1010       if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE)
1011         HDR("uniform SamplerType a_texture;");
1012       HDR("uniform vec4 ya_clamp_rect;");
1013       HDR("uniform vec4 uv_clamp_rect;");
1014       HDR("uniform float resource_multiplier;");
1015       HDR("uniform float resource_offset;");
1016       HDR("varying TexCoordPrecision vec2 v_yaTexCoord;");
1017       HDR("varying TexCoordPrecision vec2 v_uvTexCoord;");
1018       SRC("texColor.xyz -= vec3(resource_offset);");
1019       SRC("texColor.xyz *= resource_multiplier;");
1020       break;
1021     case INPUT_COLOR_SOURCE_UNIFORM:
1022       DCHECK(!ignore_sampler_type_);
1023       DCHECK(!has_rgba_fragment_tex_transform_);
1024       DCHECK(!has_tex_clamp_rect_);
1025       HDR("uniform vec4 color;");
1026       SRC("// Uniform color");
1027       SRC("vec4 texColor = color;");
1028       break;
1029   }
1030 
1031   // Apply color conversion.
1032   switch (color_conversion_mode_) {
1033     case COLOR_CONVERSION_MODE_SHADER:
1034       header += color_transform_->GetShaderSource();
1035       // Un-premultiply by alpha.
1036       if (premultiply_alpha_mode_ != NON_PREMULTIPLIED_ALPHA) {
1037         SRC("// un-premultiply alpha");
1038         SRC("if (texColor.a > 0.0) texColor.rgb /= texColor.a;");
1039       }
1040       SRC("texColor.rgb = DoColorConversion(texColor.xyz);");
1041       SRC("texColor.rgb *= texColor.a;");
1042       break;
1043     case COLOR_CONVERSION_MODE_NONE:
1044       // Premultiply by alpha.
1045       if (premultiply_alpha_mode_ == NON_PREMULTIPLIED_ALPHA) {
1046         SRC("// Premultiply alpha");
1047         SRC("texColor.rgb *= texColor.a;");
1048       }
1049       break;
1050   }
1051 
1052   // Apply the color matrix to texColor.
1053   if (has_color_matrix_) {
1054     HDR("uniform mat4 colorMatrix;");
1055     HDR("uniform vec4 colorOffset;");
1056     SRC("// Apply color matrix");
1057     SRC("float nonZeroAlpha = max(texColor.a, 0.00001);");
1058     SRC("texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);");
1059     SRC("texColor = colorMatrix * texColor + colorOffset;");
1060     SRC("texColor.rgb *= texColor.a;");
1061     SRC("texColor = clamp(texColor, 0.0, 1.0);");
1062   }
1063 
1064   // Read the mask texture.
1065   if (mask_mode_ != NO_MASK) {
1066     HDR("uniform SamplerType s_mask;");
1067     HDR("uniform vec2 maskTexCoordScale;");
1068     HDR("uniform vec2 maskTexCoordOffset;");
1069     SRC("// Read the mask");
1070     SRC("TexCoordPrecision vec2 maskTexCoord =");
1071     SRC("    vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,");
1072     SRC("         maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);");
1073     SRC("vec4 maskColor = TextureLookup(s_mask, maskTexCoord);");
1074   }
1075 
1076   // Compute AA.
1077   if (aa_mode_ == USE_AA) {
1078     HDR("varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.");
1079     SRC("// Compute AA");
1080     SRC("vec4 d4 = min(edge_dist[0], edge_dist[1]);");
1081     SRC("vec2 d2 = min(d4.xz, d4.yw);");
1082     SRC("float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);");
1083   }
1084 
1085   // Apply background texture.
1086   if (has_background_color_) {
1087     HDR("uniform vec4 background_color;");
1088     SRC("// Apply uniform background color blending");
1089     SRC("texColor += background_color * (1.0 - texColor.a);");
1090   }
1091 
1092   // Finally apply the output color matrix to texColor.
1093   if (has_output_color_matrix_) {
1094     HDR("uniform mat4 output_color_matrix;");
1095     SRC("// Apply the output color matrix");
1096     SRC("texColor = output_color_matrix * texColor;");
1097   }
1098 
1099   // Tint the final color. Used for debugging composited content.
1100   if (has_tint_color_matrix_) {
1101     HDR("uniform mat4 tint_color_matrix;");
1102     SRC("// Apply the tint color matrix");
1103     SRC("texColor = tint_color_matrix * texColor;");
1104   }
1105 
1106   // Include header text for alpha.
1107   if (has_uniform_alpha_) {
1108     HDR("uniform float alpha;");
1109   }
1110   if (has_varying_alpha_) {
1111     HDR("varying float v_alpha;");
1112   }
1113 
1114   // Apply uniform alpha, aa, varying alpha, and the mask.
1115   if (has_varying_alpha_ || aa_mode_ == USE_AA || has_uniform_alpha_ ||
1116       mask_mode_ != NO_MASK) {
1117     SRC("// Apply alpha from uniform, varying, aa, and mask.");
1118     std::string line = "  texColor = texColor";
1119     if (has_varying_alpha_)
1120       line += " * v_alpha";
1121     if (has_uniform_alpha_)
1122       line += " * alpha";
1123     if (aa_mode_ == USE_AA)
1124       line += " * aa";
1125     if (mask_mode_ != NO_MASK)
1126       line += " * maskColor.a";
1127     if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE)
1128       line += " * TextureLookup(a_texture, ya_clamped).x";
1129     line += ";\n";
1130     source += line;
1131   }
1132 
1133   // Write the fragment color.
1134   SRC("// Write the fragment color");
1135   switch (frag_color_mode_) {
1136     case FRAG_COLOR_MODE_DEFAULT:
1137       DCHECK_EQ(blend_mode_, BLEND_MODE_NONE);
1138       SRC("gl_FragColor = texColor;");
1139       break;
1140     case FRAG_COLOR_MODE_OPAQUE:
1141       DCHECK_EQ(blend_mode_, BLEND_MODE_NONE);
1142       SRC("gl_FragColor = vec4(texColor.rgb, 1.0);");
1143       break;
1144     case FRAG_COLOR_MODE_APPLY_BLEND_MODE:
1145       if (!has_blend_mode()) {
1146         SRC("gl_FragColor = texColor;");
1147       } else if (mask_mode_ != NO_MASK) {
1148         if (mask_for_background_)
1149           SRC("gl_FragColor = ApplyBlendMode(texColor, maskColor.w);");
1150         else
1151           SRC("gl_FragColor = ApplyBlendMode(texColor);");
1152       } else {
1153         SRC("gl_FragColor = ApplyBlendMode(texColor);");
1154       }
1155       break;
1156   }
1157 
1158   if (has_rounded_corner_)
1159     SRC("gl_FragColor = ApplyRoundedCorner(gl_FragColor);");
1160 
1161   source += "}\n";
1162 
1163   return header + source;
1164 }
1165 
1166 }  // namespace viz
1167