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 "cc/output/shader.h"
6
7#include <algorithm>
8
9#include "base/basictypes.h"
10#include "base/logging.h"
11#include "cc/output/gl_renderer.h"  // For the GLC() macro.
12#include "gpu/command_buffer/client/gles2_interface.h"
13#include "third_party/khronos/GLES2/gl2.h"
14
15#define SHADER0(Src) #Src
16#define VERTEX_SHADER(Src) SetVertexTexCoordPrecision(SHADER0(Src))
17#define FRAGMENT_SHADER(Src) SetFragmentTexCoordPrecision( \
18    precision, SetFragmentSamplerType(sampler, SHADER0(Src)))
19
20using gpu::gles2::GLES2Interface;
21
22namespace cc {
23
24namespace {
25
26static void GetProgramUniformLocations(GLES2Interface* context,
27                                       unsigned program,
28                                       size_t count,
29                                       const char** uniforms,
30                                       int* locations,
31                                       int* base_uniform_index) {
32  for (size_t i = 0; i < count; i++) {
33    locations[i] = (*base_uniform_index)++;
34    context->BindUniformLocationCHROMIUM(program, locations[i], uniforms[i]);
35  }
36}
37
38static std::string SetFragmentTexCoordPrecision(
39    TexCoordPrecision requested_precision, std::string shader_string) {
40  switch (requested_precision) {
41    case TexCoordPrecisionHigh:
42      DCHECK_NE(shader_string.find("TexCoordPrecision"), std::string::npos);
43      return
44          "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
45          "  #define TexCoordPrecision highp\n"
46          "#else\n"
47          "  #define TexCoordPrecision mediump\n"
48          "#endif\n" +
49          shader_string;
50    case TexCoordPrecisionMedium:
51      DCHECK_NE(shader_string.find("TexCoordPrecision"), std::string::npos);
52      return "#define TexCoordPrecision mediump\n" +
53          shader_string;
54    case TexCoordPrecisionNA:
55      DCHECK_EQ(shader_string.find("TexCoordPrecision"), std::string::npos);
56      DCHECK_EQ(shader_string.find("texture2D"), std::string::npos);
57      DCHECK_EQ(shader_string.find("texture2DRect"), std::string::npos);
58      return shader_string;
59    default:
60      NOTREACHED();
61      break;
62  }
63  return shader_string;
64}
65
66static std::string SetVertexTexCoordPrecision(const char* shader_string) {
67  // We unconditionally use highp in the vertex shader since
68  // we are unlikely to be vertex shader bound when drawing large quads.
69  // Also, some vertex shaders mutate the texture coordinate in such a
70  // way that the effective precision might be lower than expected.
71  return "#define TexCoordPrecision highp\n" +
72      std::string(shader_string);
73}
74
75TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
76                                            int *highp_threshold_cache,
77                                            int highp_threshold_min,
78                                            int x, int y) {
79  if (*highp_threshold_cache == 0) {
80    // Initialize range and precision with minimum spec values for when
81    // GetShaderPrecisionFormat is a test stub.
82    // TODO(brianderson): Implement better stubs of GetShaderPrecisionFormat
83    // everywhere.
84    GLint range[2] = { 14, 14 };
85    GLint precision = 10;
86    GLC(context, context->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER,
87                                                   GL_MEDIUM_FLOAT,
88                                                   range, &precision));
89    *highp_threshold_cache = 1 << precision;
90  }
91
92  int highp_threshold = std::max(*highp_threshold_cache, highp_threshold_min);
93  if (x > highp_threshold || y > highp_threshold)
94    return TexCoordPrecisionHigh;
95  return TexCoordPrecisionMedium;
96}
97
98static std::string SetFragmentSamplerType(
99    SamplerType requested_type, std::string shader_string) {
100  switch (requested_type) {
101    case SamplerType2D:
102      DCHECK_NE(shader_string.find("SamplerType"), std::string::npos);
103      DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos);
104      return
105          "#define SamplerType sampler2D\n"
106          "#define TextureLookup texture2D\n" +
107          shader_string;
108    case SamplerType2DRect:
109      DCHECK_NE(shader_string.find("SamplerType"), std::string::npos);
110      DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos);
111      return
112          "#extension GL_ARB_texture_rectangle : require\n"
113          "#define SamplerType sampler2DRect\n"
114          "#define TextureLookup texture2DRect\n" +
115          shader_string;
116    case SamplerTypeExternalOES:
117      DCHECK_NE(shader_string.find("SamplerType"), std::string::npos);
118      DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos);
119      return
120          "#extension GL_OES_EGL_image_external : require\n"
121          "#define SamplerType samplerExternalOES\n"
122          "#define TextureLookup texture2D\n" +
123          shader_string;
124    case SamplerTypeNA:
125      DCHECK_EQ(shader_string.find("SamplerType"), std::string::npos);
126      DCHECK_EQ(shader_string.find("TextureLookup"), std::string::npos);
127      return shader_string;
128    default:
129      NOTREACHED();
130      break;
131  }
132  return shader_string;
133}
134
135}  // namespace
136
137TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
138                                            int* highp_threshold_cache,
139                                            int highp_threshold_min,
140                                            const gfx::Point& max_coordinate) {
141  return TexCoordPrecisionRequired(context,
142                                   highp_threshold_cache, highp_threshold_min,
143                                   max_coordinate.x(), max_coordinate.y());
144}
145
146TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
147                                            int *highp_threshold_cache,
148                                            int highp_threshold_min,
149                                            const gfx::Size& max_size) {
150  return TexCoordPrecisionRequired(context,
151                                   highp_threshold_cache, highp_threshold_min,
152                                   max_size.width(), max_size.height());
153}
154
155VertexShaderPosTex::VertexShaderPosTex()
156      : matrix_location_(-1) {}
157
158void VertexShaderPosTex::Init(GLES2Interface* context,
159                              unsigned program,
160                              int* base_uniform_index) {
161  static const char* uniforms[] = {
162      "matrix",
163  };
164  int locations[arraysize(uniforms)];
165
166  GetProgramUniformLocations(context,
167                             program,
168                             arraysize(uniforms),
169                             uniforms,
170                             locations,
171                             base_uniform_index);
172  matrix_location_ = locations[0];
173}
174
175std::string VertexShaderPosTex::GetShaderString() const {
176  return VERTEX_SHADER(
177    attribute vec4 a_position;
178    attribute TexCoordPrecision vec2 a_texCoord;
179    uniform mat4 matrix;
180    varying TexCoordPrecision vec2 v_texCoord;
181    void main() {
182      gl_Position = matrix * a_position;
183      v_texCoord = a_texCoord;
184    }
185  );  // NOLINT(whitespace/parens)
186}
187
188VertexShaderPosTexYUVStretchOffset::VertexShaderPosTexYUVStretchOffset()
189    : matrix_location_(-1), tex_scale_location_(-1), tex_offset_location_(-1) {}
190
191void VertexShaderPosTexYUVStretchOffset::Init(GLES2Interface* context,
192                                              unsigned program,
193                                              int* base_uniform_index) {
194  static const char* uniforms[] = {
195    "matrix",
196    "texScale",
197    "texOffset",
198  };
199  int locations[arraysize(uniforms)];
200
201  GetProgramUniformLocations(context,
202                             program,
203                             arraysize(uniforms),
204                             uniforms,
205                             locations,
206                             base_uniform_index);
207  matrix_location_ = locations[0];
208  tex_scale_location_ = locations[1];
209  tex_offset_location_ = locations[2];
210}
211
212std::string VertexShaderPosTexYUVStretchOffset::GetShaderString() const {
213  return VERTEX_SHADER(
214    precision mediump float;
215    attribute vec4 a_position;
216    attribute TexCoordPrecision vec2 a_texCoord;
217    uniform mat4 matrix;
218    varying TexCoordPrecision vec2 v_texCoord;
219    uniform TexCoordPrecision vec2 texScale;
220    uniform TexCoordPrecision vec2 texOffset;
221    void main() {
222        gl_Position = matrix * a_position;
223        v_texCoord = a_texCoord * texScale + texOffset;
224    }
225  );  // NOLINT(whitespace/parens)
226}
227
228VertexShaderPos::VertexShaderPos()
229    : matrix_location_(-1) {}
230
231void VertexShaderPos::Init(GLES2Interface* context,
232                           unsigned program,
233                           int* base_uniform_index) {
234  static const char* uniforms[] = {
235      "matrix",
236  };
237  int locations[arraysize(uniforms)];
238
239  GetProgramUniformLocations(context,
240                             program,
241                             arraysize(uniforms),
242                             uniforms,
243                             locations,
244                             base_uniform_index);
245  matrix_location_ = locations[0];
246}
247
248std::string VertexShaderPos::GetShaderString() const {
249  return VERTEX_SHADER(
250    attribute vec4 a_position;
251    uniform mat4 matrix;
252    void main() {
253        gl_Position = matrix * a_position;
254    }
255  );  // NOLINT(whitespace/parens)
256}
257
258VertexShaderPosTexTransform::VertexShaderPosTexTransform()
259    : matrix_location_(-1),
260      tex_transform_location_(-1),
261      vertex_opacity_location_(-1) {}
262
263void VertexShaderPosTexTransform::Init(GLES2Interface* context,
264                                       unsigned program,
265                                       int* base_uniform_index) {
266  static const char* uniforms[] = {
267    "matrix",
268    "texTransform",
269    "opacity",
270  };
271  int locations[arraysize(uniforms)];
272
273  GetProgramUniformLocations(context,
274                             program,
275                             arraysize(uniforms),
276                             uniforms,
277                             locations,
278                             base_uniform_index);
279  matrix_location_ = locations[0];
280  tex_transform_location_ = locations[1];
281  vertex_opacity_location_ = locations[2];
282}
283
284std::string VertexShaderPosTexTransform::GetShaderString() const {
285  return VERTEX_SHADER(
286    attribute vec4 a_position;
287    attribute TexCoordPrecision vec2 a_texCoord;
288    attribute float a_index;
289    uniform mat4 matrix[8];
290    uniform TexCoordPrecision vec4 texTransform[8];
291    uniform float opacity[32];
292    varying TexCoordPrecision vec2 v_texCoord;
293    varying float v_alpha;
294    void main() {
295      int quad_index = int(a_index * 0.25);  // NOLINT
296      gl_Position = matrix[quad_index] * a_position;
297      TexCoordPrecision vec4 texTrans = texTransform[quad_index];
298      v_texCoord = a_texCoord * texTrans.zw + texTrans.xy;
299      v_alpha = opacity[int(a_index)]; // NOLINT
300    }
301  );  // NOLINT(whitespace/parens)
302}
303
304std::string VertexShaderPosTexIdentity::GetShaderString() const {
305  return VERTEX_SHADER(
306    attribute vec4 a_position;
307    varying TexCoordPrecision vec2 v_texCoord;
308    void main() {
309      gl_Position = a_position;
310      v_texCoord = (a_position.xy + vec2(1.0)) * 0.5;
311    }
312  );  // NOLINT(whitespace/parens)
313}
314
315VertexShaderQuad::VertexShaderQuad()
316    : matrix_location_(-1),
317      quad_location_(-1) {}
318
319void VertexShaderQuad::Init(GLES2Interface* context,
320                            unsigned program,
321                            int* base_uniform_index) {
322  static const char* uniforms[] = {
323    "matrix",
324    "quad",
325  };
326  int locations[arraysize(uniforms)];
327
328  GetProgramUniformLocations(context,
329                             program,
330                             arraysize(uniforms),
331                             uniforms,
332                             locations,
333                             base_uniform_index);
334  matrix_location_ = locations[0];
335  quad_location_ = locations[1];
336}
337
338std::string VertexShaderQuad::GetShaderString() const {
339#if defined(OS_ANDROID)
340// TODO(epenner): Find the cause of this 'quad' uniform
341// being missing if we don't add dummy variables.
342// http://crbug.com/240602
343  return VERTEX_SHADER(
344    attribute TexCoordPrecision vec4 a_position;
345    attribute float a_index;
346    uniform mat4 matrix;
347    uniform TexCoordPrecision vec2 quad[4];
348    uniform TexCoordPrecision vec2 dummy_uniform;
349    varying TexCoordPrecision vec2 dummy_varying;
350    void main() {
351      vec2 pos = quad[int(a_index)];  // NOLINT
352      gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
353      dummy_varying = dummy_uniform;
354    }
355  );  // NOLINT(whitespace/parens)
356#else
357  return VERTEX_SHADER(
358    attribute TexCoordPrecision vec4 a_position;
359    attribute float a_index;
360    uniform mat4 matrix;
361    uniform TexCoordPrecision vec2 quad[4];
362    void main() {
363      vec2 pos = quad[int(a_index)];  // NOLINT
364      gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
365    }
366  );  // NOLINT(whitespace/parens)
367#endif
368}
369
370VertexShaderQuadAA::VertexShaderQuadAA()
371    : matrix_location_(-1),
372      viewport_location_(-1),
373      quad_location_(-1),
374      edge_location_(-1) {}
375
376void VertexShaderQuadAA::Init(GLES2Interface* context,
377                            unsigned program,
378                            int* base_uniform_index) {
379  static const char* uniforms[] = {
380    "matrix",
381    "viewport",
382    "quad",
383    "edge",
384  };
385  int locations[arraysize(uniforms)];
386
387  GetProgramUniformLocations(context,
388                             program,
389                             arraysize(uniforms),
390                             uniforms,
391                             locations,
392                             base_uniform_index);
393  matrix_location_ = locations[0];
394  viewport_location_ = locations[1];
395  quad_location_ = locations[2];
396  edge_location_ = locations[3];
397}
398
399std::string VertexShaderQuadAA::GetShaderString() const {
400  return VERTEX_SHADER(
401    attribute TexCoordPrecision vec4 a_position;
402    attribute float a_index;
403    uniform mat4 matrix;
404    uniform vec4 viewport;
405    uniform TexCoordPrecision vec2 quad[4];
406    uniform TexCoordPrecision vec3 edge[8];
407    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
408
409    void main() {
410      vec2 pos = quad[int(a_index)];  // NOLINT
411      gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
412      vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
413      vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
414      edge_dist[0] = vec4(dot(edge[0], screen_pos),
415                          dot(edge[1], screen_pos),
416                          dot(edge[2], screen_pos),
417                          dot(edge[3], screen_pos)) * gl_Position.w;
418      edge_dist[1] = vec4(dot(edge[4], screen_pos),
419                          dot(edge[5], screen_pos),
420                          dot(edge[6], screen_pos),
421                          dot(edge[7], screen_pos)) * gl_Position.w;
422    }
423  );  // NOLINT(whitespace/parens)
424}
425
426VertexShaderQuadTexTransformAA::VertexShaderQuadTexTransformAA()
427    : matrix_location_(-1),
428      viewport_location_(-1),
429      quad_location_(-1),
430      edge_location_(-1),
431      tex_transform_location_(-1) {}
432
433void VertexShaderQuadTexTransformAA::Init(GLES2Interface* context,
434                                        unsigned program,
435                                        int* base_uniform_index) {
436  static const char* uniforms[] = {
437    "matrix",
438    "viewport",
439    "quad",
440    "edge",
441    "texTrans",
442  };
443  int locations[arraysize(uniforms)];
444
445  GetProgramUniformLocations(context,
446                             program,
447                             arraysize(uniforms),
448                             uniforms,
449                             locations,
450                             base_uniform_index);
451  matrix_location_ = locations[0];
452  viewport_location_ = locations[1];
453  quad_location_ = locations[2];
454  edge_location_ = locations[3];
455  tex_transform_location_ = locations[4];
456}
457
458std::string VertexShaderQuadTexTransformAA::GetShaderString() const {
459  return VERTEX_SHADER(
460    attribute TexCoordPrecision vec4 a_position;
461    attribute float a_index;
462    uniform mat4 matrix;
463    uniform vec4 viewport;
464    uniform TexCoordPrecision vec2 quad[4];
465    uniform TexCoordPrecision vec3 edge[8];
466    uniform TexCoordPrecision vec4 texTrans;
467    varying TexCoordPrecision vec2 v_texCoord;
468    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
469
470    void main() {
471      vec2 pos = quad[int(a_index)];  // NOLINT
472      gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
473      vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
474      vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
475      edge_dist[0] = vec4(dot(edge[0], screen_pos),
476                          dot(edge[1], screen_pos),
477                          dot(edge[2], screen_pos),
478                          dot(edge[3], screen_pos)) * gl_Position.w;
479      edge_dist[1] = vec4(dot(edge[4], screen_pos),
480                          dot(edge[5], screen_pos),
481                          dot(edge[6], screen_pos),
482                          dot(edge[7], screen_pos)) * gl_Position.w;
483      v_texCoord = (pos.xy + vec2(0.5)) * texTrans.zw + texTrans.xy;
484    }
485  );  // NOLINT(whitespace/parens)
486}
487
488VertexShaderTile::VertexShaderTile()
489    : matrix_location_(-1),
490      quad_location_(-1),
491      vertex_tex_transform_location_(-1) {}
492
493void VertexShaderTile::Init(GLES2Interface* context,
494                            unsigned program,
495                            int* base_uniform_index) {
496  static const char* uniforms[] = {
497    "matrix",
498    "quad",
499    "vertexTexTransform",
500  };
501  int locations[arraysize(uniforms)];
502
503  GetProgramUniformLocations(context,
504                             program,
505                             arraysize(uniforms),
506                             uniforms,
507                             locations,
508                             base_uniform_index);
509  matrix_location_ = locations[0];
510  quad_location_ = locations[1];
511  vertex_tex_transform_location_ = locations[2];
512}
513
514std::string VertexShaderTile::GetShaderString() const {
515  return VERTEX_SHADER(
516    attribute TexCoordPrecision vec4 a_position;
517    attribute float a_index;
518    uniform mat4 matrix;
519    uniform TexCoordPrecision vec2 quad[4];
520    uniform TexCoordPrecision vec4 vertexTexTransform;
521    varying TexCoordPrecision vec2 v_texCoord;
522    void main() {
523      vec2 pos = quad[int(a_index)];  // NOLINT
524      gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
525      v_texCoord = pos.xy * vertexTexTransform.zw + vertexTexTransform.xy;
526    }
527  );  // NOLINT(whitespace/parens)
528}
529
530VertexShaderTileAA::VertexShaderTileAA()
531    : matrix_location_(-1),
532      viewport_location_(-1),
533      quad_location_(-1),
534      edge_location_(-1),
535      vertex_tex_transform_location_(-1) {}
536
537void VertexShaderTileAA::Init(GLES2Interface* context,
538                              unsigned program,
539                              int* base_uniform_index) {
540  static const char* uniforms[] = {
541    "matrix",
542    "viewport",
543    "quad",
544    "edge",
545    "vertexTexTransform",
546  };
547  int locations[arraysize(uniforms)];
548
549  GetProgramUniformLocations(context,
550                             program,
551                             arraysize(uniforms),
552                             uniforms,
553                             locations,
554                             base_uniform_index);
555  matrix_location_ = locations[0];
556  viewport_location_ = locations[1];
557  quad_location_ = locations[2];
558  edge_location_ = locations[3];
559  vertex_tex_transform_location_ = locations[4];
560}
561
562std::string VertexShaderTileAA::GetShaderString() const {
563  return VERTEX_SHADER(
564    attribute TexCoordPrecision vec4 a_position;
565    attribute float a_index;
566    uniform mat4 matrix;
567    uniform vec4 viewport;
568    uniform TexCoordPrecision vec2 quad[4];
569    uniform TexCoordPrecision vec3 edge[8];
570    uniform TexCoordPrecision vec4 vertexTexTransform;
571    varying TexCoordPrecision vec2 v_texCoord;
572    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
573
574    void main() {
575      vec2 pos = quad[int(a_index)];  // NOLINT
576      gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
577      vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
578      vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
579      edge_dist[0] = vec4(dot(edge[0], screen_pos),
580                          dot(edge[1], screen_pos),
581                          dot(edge[2], screen_pos),
582                          dot(edge[3], screen_pos)) * gl_Position.w;
583      edge_dist[1] = vec4(dot(edge[4], screen_pos),
584                          dot(edge[5], screen_pos),
585                          dot(edge[6], screen_pos),
586                          dot(edge[7], screen_pos)) * gl_Position.w;
587      v_texCoord = pos.xy * vertexTexTransform.zw + vertexTexTransform.xy;
588    }
589  );  // NOLINT(whitespace/parens)
590}
591
592VertexShaderVideoTransform::VertexShaderVideoTransform()
593    : matrix_location_(-1),
594      tex_matrix_location_(-1) {}
595
596void VertexShaderVideoTransform::Init(GLES2Interface* context,
597                                      unsigned program,
598                                      int* base_uniform_index) {
599  static const char* uniforms[] = {
600    "matrix",
601    "texMatrix",
602  };
603  int locations[arraysize(uniforms)];
604
605  GetProgramUniformLocations(context,
606                             program,
607                             arraysize(uniforms),
608                             uniforms,
609                             locations,
610                             base_uniform_index);
611  matrix_location_ = locations[0];
612  tex_matrix_location_ = locations[1];
613}
614
615std::string VertexShaderVideoTransform::GetShaderString() const {
616  return VERTEX_SHADER(
617    attribute vec4 a_position;
618    attribute TexCoordPrecision vec2 a_texCoord;
619    uniform mat4 matrix;
620    uniform TexCoordPrecision mat4 texMatrix;
621    varying TexCoordPrecision vec2 v_texCoord;
622    void main() {
623        gl_Position = matrix * a_position;
624        v_texCoord =
625            vec2(texMatrix * vec4(a_texCoord.x, 1.0 - a_texCoord.y, 0.0, 1.0));
626    }
627  );  // NOLINT(whitespace/parens)
628}
629
630FragmentTexAlphaBinding::FragmentTexAlphaBinding()
631    : sampler_location_(-1),
632      alpha_location_(-1) {}
633
634void FragmentTexAlphaBinding::Init(GLES2Interface* context,
635                                   unsigned program,
636                                   int* base_uniform_index) {
637  static const char* uniforms[] = {
638    "s_texture",
639    "alpha",
640  };
641  int locations[arraysize(uniforms)];
642
643  GetProgramUniformLocations(context,
644                             program,
645                             arraysize(uniforms),
646                             uniforms,
647                             locations,
648                             base_uniform_index);
649  sampler_location_ = locations[0];
650  alpha_location_ = locations[1];
651}
652
653FragmentTexColorMatrixAlphaBinding::FragmentTexColorMatrixAlphaBinding()
654    : sampler_location_(-1),
655      alpha_location_(-1),
656      color_matrix_location_(-1),
657      color_offset_location_(-1) {}
658
659void FragmentTexColorMatrixAlphaBinding::Init(GLES2Interface* context,
660                                              unsigned program,
661                                              int* base_uniform_index) {
662  static const char* uniforms[] = {
663    "s_texture",
664    "alpha",
665    "colorMatrix",
666    "colorOffset",
667  };
668  int locations[arraysize(uniforms)];
669
670  GetProgramUniformLocations(context,
671                             program,
672                             arraysize(uniforms),
673                             uniforms,
674                             locations,
675                             base_uniform_index);
676  sampler_location_ = locations[0];
677  alpha_location_ = locations[1];
678  color_matrix_location_ = locations[2];
679  color_offset_location_ = locations[3];
680}
681
682FragmentTexOpaqueBinding::FragmentTexOpaqueBinding()
683    : sampler_location_(-1) {}
684
685void FragmentTexOpaqueBinding::Init(GLES2Interface* context,
686                                    unsigned program,
687                                    int* base_uniform_index) {
688  static const char* uniforms[] = {
689    "s_texture",
690  };
691  int locations[arraysize(uniforms)];
692
693  GetProgramUniformLocations(context,
694                             program,
695                             arraysize(uniforms),
696                             uniforms,
697                             locations,
698                             base_uniform_index);
699  sampler_location_ = locations[0];
700}
701
702std::string FragmentShaderRGBATexAlpha::GetShaderString(
703    TexCoordPrecision precision, SamplerType sampler) const {
704  return FRAGMENT_SHADER(
705    precision mediump float;
706    varying TexCoordPrecision vec2 v_texCoord;
707    uniform SamplerType s_texture;
708    uniform float alpha;
709    void main() {
710      vec4 texColor = TextureLookup(s_texture, v_texCoord);
711      gl_FragColor = texColor * alpha;
712    }
713  );  // NOLINT(whitespace/parens)
714}
715
716std::string FragmentShaderRGBATexColorMatrixAlpha::GetShaderString(
717    TexCoordPrecision precision, SamplerType sampler) const {
718  return FRAGMENT_SHADER(
719    precision mediump float;
720    varying TexCoordPrecision vec2 v_texCoord;
721    uniform SamplerType s_texture;
722    uniform float alpha;
723    uniform mat4 colorMatrix;
724    uniform vec4 colorOffset;
725    void main() {
726      vec4 texColor = TextureLookup(s_texture, v_texCoord);
727      float nonZeroAlpha = max(texColor.a, 0.00001);
728      texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
729      texColor = colorMatrix * texColor + colorOffset;
730      texColor.rgb *= texColor.a;
731      texColor = clamp(texColor, 0.0, 1.0);
732      gl_FragColor = texColor * alpha;
733    }
734  );  // NOLINT(whitespace/parens)
735}
736
737std::string FragmentShaderRGBATexVaryingAlpha::GetShaderString(
738    TexCoordPrecision precision, SamplerType sampler) const {
739  return FRAGMENT_SHADER(
740    precision mediump float;
741    varying TexCoordPrecision vec2 v_texCoord;
742    varying float v_alpha;
743    uniform SamplerType s_texture;
744    void main() {
745      vec4 texColor = TextureLookup(s_texture, v_texCoord);
746      gl_FragColor = texColor * v_alpha;
747    }
748  );  // NOLINT(whitespace/parens)
749}
750
751std::string FragmentShaderRGBATexPremultiplyAlpha::GetShaderString(
752    TexCoordPrecision precision, SamplerType sampler) const {
753  return FRAGMENT_SHADER(
754    precision mediump float;
755    varying TexCoordPrecision vec2 v_texCoord;
756    varying float v_alpha;
757    uniform SamplerType s_texture;
758    void main() {
759      vec4 texColor = TextureLookup(s_texture, v_texCoord);
760      texColor.rgb *= texColor.a;
761      gl_FragColor = texColor * v_alpha;
762    }
763  );  // NOLINT(whitespace/parens)
764}
765
766FragmentTexBackgroundBinding::FragmentTexBackgroundBinding()
767    : background_color_location_(-1),
768      sampler_location_(-1) {
769}
770
771void FragmentTexBackgroundBinding::Init(GLES2Interface* context,
772                                        unsigned program,
773                                        int* base_uniform_index) {
774  static const char* uniforms[] = {
775    "s_texture",
776    "background_color",
777  };
778  int locations[arraysize(uniforms)];
779
780  GetProgramUniformLocations(context,
781                             program,
782                             arraysize(uniforms),
783                             uniforms,
784                             locations,
785                             base_uniform_index);
786
787  sampler_location_ = locations[0];
788  DCHECK_NE(sampler_location_, -1);
789
790  background_color_location_ = locations[1];
791  DCHECK_NE(background_color_location_, -1);
792}
793
794std::string FragmentShaderTexBackgroundVaryingAlpha::GetShaderString(
795    TexCoordPrecision precision, SamplerType sampler) const {
796  return FRAGMENT_SHADER(
797    precision mediump float;
798    varying TexCoordPrecision vec2 v_texCoord;
799    varying float v_alpha;
800    uniform vec4 background_color;
801    uniform SamplerType s_texture;
802    void main() {
803      vec4 texColor = TextureLookup(s_texture, v_texCoord);
804      texColor += background_color * (1.0 - texColor.a);
805      gl_FragColor = texColor * v_alpha;
806    }
807  );  // NOLINT(whitespace/parens)
808}
809
810std::string FragmentShaderTexBackgroundPremultiplyAlpha::GetShaderString(
811    TexCoordPrecision precision, SamplerType sampler) const {
812  return FRAGMENT_SHADER(
813    precision mediump float;
814    varying TexCoordPrecision vec2 v_texCoord;
815    varying float v_alpha;
816    uniform vec4 background_color;
817    uniform SamplerType s_texture;
818    void main() {
819      vec4 texColor = TextureLookup(s_texture, v_texCoord);
820      texColor.rgb *= texColor.a;
821      texColor += background_color * (1.0 - texColor.a);
822      gl_FragColor = texColor * v_alpha;
823    }
824  );  // NOLINT(whitespace/parens)
825}
826
827std::string FragmentShaderRGBATexOpaque::GetShaderString(
828    TexCoordPrecision precision, SamplerType sampler) const {
829  return FRAGMENT_SHADER(
830    precision mediump float;
831    varying TexCoordPrecision vec2 v_texCoord;
832    uniform SamplerType s_texture;
833    void main() {
834      vec4 texColor = TextureLookup(s_texture, v_texCoord);
835      gl_FragColor = vec4(texColor.rgb, 1.0);
836    }
837  );  // NOLINT(whitespace/parens)
838}
839
840std::string FragmentShaderRGBATex::GetShaderString(
841    TexCoordPrecision precision, SamplerType sampler) const {
842  return FRAGMENT_SHADER(
843    precision mediump float;
844    varying TexCoordPrecision vec2 v_texCoord;
845    uniform SamplerType s_texture;
846    void main() {
847      gl_FragColor = TextureLookup(s_texture, v_texCoord);
848    }
849  );  // NOLINT(whitespace/parens)
850}
851
852std::string FragmentShaderRGBATexSwizzleAlpha::GetShaderString(
853    TexCoordPrecision precision, SamplerType sampler) const {
854  return FRAGMENT_SHADER(
855    precision mediump float;
856    varying TexCoordPrecision vec2 v_texCoord;
857    uniform SamplerType s_texture;
858    uniform float alpha;
859    void main() {
860        vec4 texColor = TextureLookup(s_texture, v_texCoord);
861        gl_FragColor =
862            vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha;
863    }
864  );  // NOLINT(whitespace/parens)
865}
866
867std::string FragmentShaderRGBATexSwizzleOpaque::GetShaderString(
868    TexCoordPrecision precision, SamplerType sampler) const {
869  return FRAGMENT_SHADER(
870    precision mediump float;
871    varying TexCoordPrecision vec2 v_texCoord;
872    uniform SamplerType s_texture;
873    void main() {
874      vec4 texColor = TextureLookup(s_texture, v_texCoord);
875      gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, 1.0);
876    }
877  );  // NOLINT(whitespace/parens)
878}
879
880FragmentShaderRGBATexAlphaAA::FragmentShaderRGBATexAlphaAA()
881    : sampler_location_(-1),
882      alpha_location_(-1) {}
883
884void FragmentShaderRGBATexAlphaAA::Init(GLES2Interface* context,
885                                        unsigned program,
886                                        int* base_uniform_index) {
887  static const char* uniforms[] = {
888    "s_texture",
889    "alpha",
890  };
891  int locations[arraysize(uniforms)];
892
893  GetProgramUniformLocations(context,
894                             program,
895                             arraysize(uniforms),
896                             uniforms,
897                             locations,
898                             base_uniform_index);
899  sampler_location_ = locations[0];
900  alpha_location_ = locations[1];
901}
902
903std::string FragmentShaderRGBATexAlphaAA::GetShaderString(
904    TexCoordPrecision precision, SamplerType sampler) const {
905  return FRAGMENT_SHADER(
906    precision mediump float;
907    uniform SamplerType s_texture;
908    uniform float alpha;
909    varying TexCoordPrecision vec2 v_texCoord;
910    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
911
912    void main() {
913      vec4 texColor = TextureLookup(s_texture, v_texCoord);
914      vec4 d4 = min(edge_dist[0], edge_dist[1]);
915      vec2 d2 = min(d4.xz, d4.yw);
916      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
917      gl_FragColor = texColor * alpha * aa;
918    }
919  );  // NOLINT(whitespace/parens)
920}
921
922FragmentTexClampAlphaAABinding::FragmentTexClampAlphaAABinding()
923    : sampler_location_(-1),
924      alpha_location_(-1),
925      fragment_tex_transform_location_(-1) {}
926
927void FragmentTexClampAlphaAABinding::Init(GLES2Interface* context,
928                                          unsigned program,
929                                          int* base_uniform_index) {
930  static const char* uniforms[] = {
931    "s_texture",
932    "alpha",
933    "fragmentTexTransform",
934  };
935  int locations[arraysize(uniforms)];
936
937  GetProgramUniformLocations(context,
938                             program,
939                             arraysize(uniforms),
940                             uniforms,
941                             locations,
942                             base_uniform_index);
943  sampler_location_ = locations[0];
944  alpha_location_ = locations[1];
945  fragment_tex_transform_location_ = locations[2];
946}
947
948std::string FragmentShaderRGBATexClampAlphaAA::GetShaderString(
949    TexCoordPrecision precision, SamplerType sampler) const {
950  return FRAGMENT_SHADER(
951    precision mediump float;
952    uniform SamplerType s_texture;
953    uniform float alpha;
954    uniform TexCoordPrecision vec4 fragmentTexTransform;
955    varying TexCoordPrecision vec2 v_texCoord;
956    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
957
958    void main() {
959      TexCoordPrecision vec2 texCoord =
960          clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw +
961          fragmentTexTransform.xy;
962      vec4 texColor = TextureLookup(s_texture, texCoord);
963      vec4 d4 = min(edge_dist[0], edge_dist[1]);
964      vec2 d2 = min(d4.xz, d4.yw);
965      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
966      gl_FragColor = texColor * alpha * aa;
967    }
968  );  // NOLINT(whitespace/parens)
969}
970
971std::string FragmentShaderRGBATexClampSwizzleAlphaAA::GetShaderString(
972    TexCoordPrecision precision, SamplerType sampler) const {
973  return FRAGMENT_SHADER(
974    precision mediump float;
975    uniform SamplerType s_texture;
976    uniform float alpha;
977    uniform TexCoordPrecision vec4 fragmentTexTransform;
978    varying TexCoordPrecision vec2 v_texCoord;
979    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
980
981    void main() {
982      TexCoordPrecision vec2 texCoord =
983          clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw +
984          fragmentTexTransform.xy;
985      vec4 texColor = TextureLookup(s_texture, texCoord);
986      vec4 d4 = min(edge_dist[0], edge_dist[1]);
987      vec2 d2 = min(d4.xz, d4.yw);
988      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
989      gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, texColor.w) *
990          alpha * aa;
991    }
992  );  // NOLINT(whitespace/parens)
993}
994
995FragmentShaderRGBATexAlphaMask::FragmentShaderRGBATexAlphaMask()
996    : sampler_location_(-1),
997      mask_sampler_location_(-1),
998      alpha_location_(-1),
999      mask_tex_coord_scale_location_(-1) {}
1000
1001void FragmentShaderRGBATexAlphaMask::Init(GLES2Interface* context,
1002                                          unsigned program,
1003                                          int* base_uniform_index) {
1004  static const char* uniforms[] = {
1005    "s_texture",
1006    "s_mask",
1007    "alpha",
1008    "maskTexCoordScale",
1009    "maskTexCoordOffset",
1010  };
1011  int locations[arraysize(uniforms)];
1012
1013  GetProgramUniformLocations(context,
1014                             program,
1015                             arraysize(uniforms),
1016                             uniforms,
1017                             locations,
1018                             base_uniform_index);
1019  sampler_location_ = locations[0];
1020  mask_sampler_location_ = locations[1];
1021  alpha_location_ = locations[2];
1022  mask_tex_coord_scale_location_ = locations[3];
1023  mask_tex_coord_offset_location_ = locations[4];
1024}
1025
1026std::string FragmentShaderRGBATexAlphaMask::GetShaderString(
1027    TexCoordPrecision precision, SamplerType sampler) const {
1028  return FRAGMENT_SHADER(
1029    precision mediump float;
1030    varying TexCoordPrecision vec2 v_texCoord;
1031    uniform SamplerType s_texture;
1032    uniform SamplerType s_mask;
1033    uniform TexCoordPrecision vec2 maskTexCoordScale;
1034    uniform TexCoordPrecision vec2 maskTexCoordOffset;
1035    uniform float alpha;
1036    void main() {
1037      vec4 texColor = TextureLookup(s_texture, v_texCoord);
1038      TexCoordPrecision vec2 maskTexCoord =
1039          vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
1040               maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
1041      vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
1042      gl_FragColor = texColor * alpha * maskColor.w;
1043    }
1044  );  // NOLINT(whitespace/parens)
1045}
1046
1047FragmentShaderRGBATexAlphaMaskAA::FragmentShaderRGBATexAlphaMaskAA()
1048    : sampler_location_(-1),
1049      mask_sampler_location_(-1),
1050      alpha_location_(-1),
1051      mask_tex_coord_scale_location_(-1),
1052      mask_tex_coord_offset_location_(-1) {}
1053
1054void FragmentShaderRGBATexAlphaMaskAA::Init(GLES2Interface* context,
1055                                            unsigned program,
1056                                            int* base_uniform_index) {
1057  static const char* uniforms[] = {
1058    "s_texture",
1059    "s_mask",
1060    "alpha",
1061    "maskTexCoordScale",
1062    "maskTexCoordOffset",
1063  };
1064  int locations[arraysize(uniforms)];
1065
1066  GetProgramUniformLocations(context,
1067                             program,
1068                             arraysize(uniforms),
1069                             uniforms,
1070                             locations,
1071                             base_uniform_index);
1072  sampler_location_ = locations[0];
1073  mask_sampler_location_ = locations[1];
1074  alpha_location_ = locations[2];
1075  mask_tex_coord_scale_location_ = locations[3];
1076  mask_tex_coord_offset_location_ = locations[4];
1077}
1078
1079std::string FragmentShaderRGBATexAlphaMaskAA::GetShaderString(
1080    TexCoordPrecision precision, SamplerType sampler) const {
1081  return FRAGMENT_SHADER(
1082    precision mediump float;
1083    uniform SamplerType s_texture;
1084    uniform SamplerType s_mask;
1085    uniform TexCoordPrecision vec2 maskTexCoordScale;
1086    uniform TexCoordPrecision vec2 maskTexCoordOffset;
1087    uniform float alpha;
1088    varying TexCoordPrecision vec2 v_texCoord;
1089    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
1090
1091    void main() {
1092      vec4 texColor = TextureLookup(s_texture, v_texCoord);
1093      TexCoordPrecision vec2 maskTexCoord =
1094          vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
1095               maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
1096      vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
1097      vec4 d4 = min(edge_dist[0], edge_dist[1]);
1098      vec2 d2 = min(d4.xz, d4.yw);
1099      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
1100      gl_FragColor = texColor * alpha * maskColor.w * aa;
1101    }
1102  );  // NOLINT(whitespace/parens)
1103}
1104
1105FragmentShaderRGBATexAlphaMaskColorMatrixAA::
1106    FragmentShaderRGBATexAlphaMaskColorMatrixAA()
1107        : sampler_location_(-1),
1108          mask_sampler_location_(-1),
1109          alpha_location_(-1),
1110          mask_tex_coord_scale_location_(-1),
1111          color_matrix_location_(-1),
1112          color_offset_location_(-1) {}
1113
1114void FragmentShaderRGBATexAlphaMaskColorMatrixAA::Init(
1115    GLES2Interface* context,
1116    unsigned program,
1117    int* base_uniform_index) {
1118  static const char* uniforms[] = {
1119    "s_texture",
1120    "s_mask",
1121    "alpha",
1122    "maskTexCoordScale",
1123    "maskTexCoordOffset",
1124    "colorMatrix",
1125    "colorOffset",
1126  };
1127  int locations[arraysize(uniforms)];
1128
1129  GetProgramUniformLocations(context,
1130                             program,
1131                             arraysize(uniforms),
1132                             uniforms,
1133                             locations,
1134                             base_uniform_index);
1135  sampler_location_ = locations[0];
1136  mask_sampler_location_ = locations[1];
1137  alpha_location_ = locations[2];
1138  mask_tex_coord_scale_location_ = locations[3];
1139  mask_tex_coord_offset_location_ = locations[4];
1140  color_matrix_location_ = locations[5];
1141  color_offset_location_ = locations[6];
1142}
1143
1144std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderString(
1145    TexCoordPrecision precision, SamplerType sampler) const {
1146  return FRAGMENT_SHADER(
1147    precision mediump float;
1148    uniform SamplerType s_texture;
1149    uniform SamplerType s_mask;
1150    uniform vec2 maskTexCoordScale;
1151    uniform vec2 maskTexCoordOffset;
1152    uniform mat4 colorMatrix;
1153    uniform vec4 colorOffset;
1154    uniform float alpha;
1155    varying TexCoordPrecision vec2 v_texCoord;
1156    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
1157
1158    void main() {
1159      vec4 texColor = TextureLookup(s_texture, v_texCoord);
1160      float nonZeroAlpha = max(texColor.a, 0.00001);
1161      texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
1162      texColor = colorMatrix * texColor + colorOffset;
1163      texColor.rgb *= texColor.a;
1164      texColor = clamp(texColor, 0.0, 1.0);
1165      TexCoordPrecision vec2 maskTexCoord =
1166          vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
1167               maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
1168      vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
1169      vec4 d4 = min(edge_dist[0], edge_dist[1]);
1170      vec2 d2 = min(d4.xz, d4.yw);
1171      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
1172      gl_FragColor = texColor * alpha * maskColor.w * aa;
1173    }
1174  );  // NOLINT(whitespace/parens)
1175}
1176
1177FragmentShaderRGBATexAlphaColorMatrixAA::
1178    FragmentShaderRGBATexAlphaColorMatrixAA()
1179        : sampler_location_(-1),
1180          alpha_location_(-1),
1181          color_matrix_location_(-1),
1182          color_offset_location_(-1) {}
1183
1184void FragmentShaderRGBATexAlphaColorMatrixAA::Init(
1185      GLES2Interface* context,
1186      unsigned program,
1187      int* base_uniform_index) {
1188  static const char* uniforms[] = {
1189    "s_texture",
1190    "alpha",
1191    "colorMatrix",
1192    "colorOffset",
1193  };
1194  int locations[arraysize(uniforms)];
1195
1196  GetProgramUniformLocations(context,
1197                             program,
1198                             arraysize(uniforms),
1199                             uniforms,
1200                             locations,
1201                             base_uniform_index);
1202  sampler_location_ = locations[0];
1203  alpha_location_ = locations[1];
1204  color_matrix_location_ = locations[2];
1205  color_offset_location_ = locations[3];
1206}
1207
1208std::string FragmentShaderRGBATexAlphaColorMatrixAA::GetShaderString(
1209    TexCoordPrecision precision, SamplerType sampler) const {
1210  return FRAGMENT_SHADER(
1211    precision mediump float;
1212    uniform SamplerType s_texture;
1213    uniform float alpha;
1214    uniform mat4 colorMatrix;
1215    uniform vec4 colorOffset;
1216    varying TexCoordPrecision vec2 v_texCoord;
1217    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
1218
1219    void main() {
1220      vec4 texColor = TextureLookup(s_texture, v_texCoord);
1221      float nonZeroAlpha = max(texColor.a, 0.00001);
1222      texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
1223      texColor = colorMatrix * texColor + colorOffset;
1224      texColor.rgb *= texColor.a;
1225      texColor = clamp(texColor, 0.0, 1.0);
1226      vec4 d4 = min(edge_dist[0], edge_dist[1]);
1227      vec2 d2 = min(d4.xz, d4.yw);
1228      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
1229      gl_FragColor = texColor * alpha * aa;
1230    }
1231  );  // NOLINT(whitespace/parens)
1232}
1233
1234FragmentShaderRGBATexAlphaMaskColorMatrix::
1235    FragmentShaderRGBATexAlphaMaskColorMatrix()
1236        : sampler_location_(-1),
1237          mask_sampler_location_(-1),
1238          alpha_location_(-1),
1239          mask_tex_coord_scale_location_(-1) {}
1240
1241void FragmentShaderRGBATexAlphaMaskColorMatrix::Init(
1242    GLES2Interface* context,
1243    unsigned program,
1244    int* base_uniform_index) {
1245  static const char* uniforms[] = {
1246    "s_texture",
1247    "s_mask",
1248    "alpha",
1249    "maskTexCoordScale",
1250    "maskTexCoordOffset",
1251    "colorMatrix",
1252    "colorOffset",
1253  };
1254  int locations[arraysize(uniforms)];
1255
1256  GetProgramUniformLocations(context,
1257                             program,
1258                             arraysize(uniforms),
1259                             uniforms,
1260                             locations,
1261                             base_uniform_index);
1262  sampler_location_ = locations[0];
1263  mask_sampler_location_ = locations[1];
1264  alpha_location_ = locations[2];
1265  mask_tex_coord_scale_location_ = locations[3];
1266  mask_tex_coord_offset_location_ = locations[4];
1267  color_matrix_location_ = locations[5];
1268  color_offset_location_ = locations[6];
1269}
1270
1271std::string FragmentShaderRGBATexAlphaMaskColorMatrix::GetShaderString(
1272    TexCoordPrecision precision, SamplerType sampler) const {
1273  return FRAGMENT_SHADER(
1274    precision mediump float;
1275    varying TexCoordPrecision vec2 v_texCoord;
1276    uniform SamplerType s_texture;
1277    uniform SamplerType s_mask;
1278    uniform vec2 maskTexCoordScale;
1279    uniform vec2 maskTexCoordOffset;
1280    uniform mat4 colorMatrix;
1281    uniform vec4 colorOffset;
1282    uniform float alpha;
1283    void main() {
1284      vec4 texColor = TextureLookup(s_texture, v_texCoord);
1285      float nonZeroAlpha = max(texColor.a, 0.00001);
1286      texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
1287      texColor = colorMatrix * texColor + colorOffset;
1288      texColor.rgb *= texColor.a;
1289      texColor = clamp(texColor, 0.0, 1.0);
1290      TexCoordPrecision vec2 maskTexCoord =
1291          vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
1292               maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
1293      vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
1294      gl_FragColor = texColor * alpha * maskColor.w;
1295    }
1296  );  // NOLINT(whitespace/parens)
1297}
1298
1299FragmentShaderYUVVideo::FragmentShaderYUVVideo()
1300    : y_texture_location_(-1),
1301      u_texture_location_(-1),
1302      v_texture_location_(-1),
1303      alpha_location_(-1),
1304      yuv_matrix_location_(-1),
1305      yuv_adj_location_(-1) {}
1306
1307void FragmentShaderYUVVideo::Init(GLES2Interface* context,
1308                                  unsigned program,
1309                                  int* base_uniform_index) {
1310  static const char* uniforms[] = {
1311    "y_texture",
1312    "u_texture",
1313    "v_texture",
1314    "alpha",
1315    "yuv_matrix",
1316    "yuv_adj",
1317  };
1318  int locations[arraysize(uniforms)];
1319
1320  GetProgramUniformLocations(context,
1321                             program,
1322                             arraysize(uniforms),
1323                             uniforms,
1324                             locations,
1325                             base_uniform_index);
1326  y_texture_location_ = locations[0];
1327  u_texture_location_ = locations[1];
1328  v_texture_location_ = locations[2];
1329  alpha_location_ = locations[3];
1330  yuv_matrix_location_ = locations[4];
1331  yuv_adj_location_ = locations[5];
1332}
1333
1334std::string FragmentShaderYUVVideo::GetShaderString(
1335    TexCoordPrecision precision, SamplerType sampler) const {
1336  return FRAGMENT_SHADER(
1337    precision mediump float;
1338    precision mediump int;
1339    varying TexCoordPrecision vec2 v_texCoord;
1340    uniform SamplerType y_texture;
1341    uniform SamplerType u_texture;
1342    uniform SamplerType v_texture;
1343    uniform float alpha;
1344    uniform vec3 yuv_adj;
1345    uniform mat3 yuv_matrix;
1346    void main() {
1347      float y_raw = TextureLookup(y_texture, v_texCoord).x;
1348      float u_unsigned = TextureLookup(u_texture, v_texCoord).x;
1349      float v_unsigned = TextureLookup(v_texture, v_texCoord).x;
1350      vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;
1351      vec3 rgb = yuv_matrix * yuv;
1352      gl_FragColor = vec4(rgb, 1.0) * alpha;
1353    }
1354  );  // NOLINT(whitespace/parens)
1355}
1356
1357FragmentShaderYUVAVideo::FragmentShaderYUVAVideo()
1358    : y_texture_location_(-1),
1359      u_texture_location_(-1),
1360      v_texture_location_(-1),
1361      a_texture_location_(-1),
1362      alpha_location_(-1),
1363      yuv_matrix_location_(-1),
1364      yuv_adj_location_(-1) {
1365}
1366
1367void FragmentShaderYUVAVideo::Init(GLES2Interface* context,
1368                                   unsigned program,
1369                                   int* base_uniform_index) {
1370  static const char* uniforms[] = {
1371      "y_texture",
1372      "u_texture",
1373      "v_texture",
1374      "a_texture",
1375      "alpha",
1376      "cc_matrix",
1377      "yuv_adj",
1378  };
1379  int locations[arraysize(uniforms)];
1380
1381  GetProgramUniformLocations(context,
1382                             program,
1383                             arraysize(uniforms),
1384                             uniforms,
1385                             locations,
1386                             base_uniform_index);
1387  y_texture_location_ = locations[0];
1388  u_texture_location_ = locations[1];
1389  v_texture_location_ = locations[2];
1390  a_texture_location_ = locations[3];
1391  alpha_location_ = locations[4];
1392  yuv_matrix_location_ = locations[5];
1393  yuv_adj_location_ = locations[6];
1394}
1395
1396std::string FragmentShaderYUVAVideo::GetShaderString(
1397    TexCoordPrecision precision, SamplerType sampler) const {
1398  return FRAGMENT_SHADER(
1399    precision mediump float;
1400    precision mediump int;
1401    varying TexCoordPrecision vec2 v_texCoord;
1402    uniform SamplerType y_texture;
1403    uniform SamplerType u_texture;
1404    uniform SamplerType v_texture;
1405    uniform SamplerType a_texture;
1406    uniform float alpha;
1407    uniform vec3 yuv_adj;
1408    uniform mat3 yuv_matrix;
1409    void main() {
1410      float y_raw = TextureLookup(y_texture, v_texCoord).x;
1411      float u_unsigned = TextureLookup(u_texture, v_texCoord).x;
1412      float v_unsigned = TextureLookup(v_texture, v_texCoord).x;
1413      float a_raw = TextureLookup(a_texture, v_texCoord).x;
1414      vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;
1415      vec3 rgb = yuv_matrix * yuv;
1416      gl_FragColor = vec4(rgb, 1.0) * (alpha * a_raw);
1417    }
1418  );  // NOLINT(whitespace/parens)
1419}
1420
1421FragmentShaderColor::FragmentShaderColor()
1422    : color_location_(-1) {}
1423
1424void FragmentShaderColor::Init(GLES2Interface* context,
1425                               unsigned program,
1426                               int* base_uniform_index) {
1427  static const char* uniforms[] = {
1428    "color",
1429  };
1430  int locations[arraysize(uniforms)];
1431
1432  GetProgramUniformLocations(context,
1433                             program,
1434                             arraysize(uniforms),
1435                             uniforms,
1436                             locations,
1437                             base_uniform_index);
1438  color_location_ = locations[0];
1439}
1440
1441std::string FragmentShaderColor::GetShaderString(
1442    TexCoordPrecision precision, SamplerType sampler) const {
1443  return FRAGMENT_SHADER(
1444    precision mediump float;
1445    uniform vec4 color;
1446    void main() {
1447      gl_FragColor = color;
1448    }
1449  );  // NOLINT(whitespace/parens)
1450}
1451
1452FragmentShaderColorAA::FragmentShaderColorAA()
1453    : color_location_(-1) {}
1454
1455void FragmentShaderColorAA::Init(GLES2Interface* context,
1456                                 unsigned program,
1457                                 int* base_uniform_index) {
1458  static const char* uniforms[] = {
1459    "color",
1460  };
1461  int locations[arraysize(uniforms)];
1462
1463  GetProgramUniformLocations(context,
1464                             program,
1465                             arraysize(uniforms),
1466                             uniforms,
1467                             locations,
1468                             base_uniform_index);
1469  color_location_ = locations[0];
1470}
1471
1472std::string FragmentShaderColorAA::GetShaderString(
1473    TexCoordPrecision precision, SamplerType sampler) const {
1474  return FRAGMENT_SHADER(
1475    precision mediump float;
1476    uniform vec4 color;
1477    varying vec4 edge_dist[2];  // 8 edge distances.
1478
1479    void main() {
1480      vec4 d4 = min(edge_dist[0], edge_dist[1]);
1481      vec2 d2 = min(d4.xz, d4.yw);
1482      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
1483      gl_FragColor = color * aa;
1484    }
1485  );  // NOLINT(whitespace/parens)
1486}
1487
1488FragmentShaderCheckerboard::FragmentShaderCheckerboard()
1489    : alpha_location_(-1),
1490      tex_transform_location_(-1),
1491      frequency_location_(-1) {}
1492
1493void FragmentShaderCheckerboard::Init(GLES2Interface* context,
1494                                      unsigned program,
1495                                      int* base_uniform_index) {
1496  static const char* uniforms[] = {
1497    "alpha",
1498    "texTransform",
1499    "frequency",
1500    "color",
1501  };
1502  int locations[arraysize(uniforms)];
1503
1504  GetProgramUniformLocations(context,
1505                             program,
1506                             arraysize(uniforms),
1507                             uniforms,
1508                             locations,
1509                             base_uniform_index);
1510  alpha_location_ = locations[0];
1511  tex_transform_location_ = locations[1];
1512  frequency_location_ = locations[2];
1513  color_location_ = locations[3];
1514}
1515
1516std::string FragmentShaderCheckerboard::GetShaderString(
1517    TexCoordPrecision precision, SamplerType sampler) const {
1518  // Shader based on Example 13-17 of "OpenGL ES 2.0 Programming Guide"
1519  // by Munshi, Ginsburg, Shreiner.
1520  return FRAGMENT_SHADER(
1521    precision mediump float;
1522    precision mediump int;
1523    varying vec2 v_texCoord;
1524    uniform float alpha;
1525    uniform float frequency;
1526    uniform vec4 texTransform;
1527    uniform vec4 color;
1528    void main() {
1529      vec4 color1 = vec4(1.0, 1.0, 1.0, 1.0);
1530      vec4 color2 = color;
1531      vec2 texCoord =
1532          clamp(v_texCoord, 0.0, 1.0) * texTransform.zw + texTransform.xy;
1533      vec2 coord = mod(floor(texCoord * frequency * 2.0), 2.0);
1534      float picker = abs(coord.x - coord.y);  // NOLINT
1535      gl_FragColor = mix(color1, color2, picker) * alpha;
1536    }
1537  );  // NOLINT(whitespace/parens)
1538}
1539
1540}  // namespace cc
1541