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