132e97315e2a55557ad7c372239e0823a81243221zmo@google.com//
232e97315e2a55557ad7c372239e0823a81243221zmo@google.com// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
332e97315e2a55557ad7c372239e0823a81243221zmo@google.com// Use of this source code is governed by a BSD-style license that can be
432e97315e2a55557ad7c372239e0823a81243221zmo@google.com// found in the LICENSE file.
532e97315e2a55557ad7c372239e0823a81243221zmo@google.com//
632e97315e2a55557ad7c372239e0823a81243221zmo@google.com
7183bde5527317fa2208401e5e6b803ef51a0fdcbJamie Madill#include "angle_gl.h"
817732823f9c21bdba9cc51ffaceb545ce3857a8cGeoff Lang#include "compiler/translator/BuiltInFunctionEmulator.h"
917732823f9c21bdba9cc51ffaceb545ce3857a8cGeoff Lang#include "compiler/translator/SymbolTable.h"
1032e97315e2a55557ad7c372239e0823a81243221zmo@google.com
1132e97315e2a55557ad7c372239e0823a81243221zmo@google.comnamespace {
1232e97315e2a55557ad7c372239e0823a81243221zmo@google.com
13a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com// we use macros here instead of function definitions to work around more GLSL
14a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com// compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are
15a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com// problematic because if the argument has side-effects they will be repeatedly
16a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com// evaluated. This is unlikely to show up in real shaders, but is something to
17a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com// consider.
18a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.comconst char* kFunctionEmulationVertexSource[] = {
19a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for cos(float)",
20a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for cos(vec2)",
21a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for cos(vec3)",
22a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for cos(vec4)",
23a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com
24a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
25a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for distance(vec2, vec2)",
26a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for distance(vec3, vec3)",
27a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for distance(vec4, vec4)",
28a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com
29a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#define webgl_dot_emu(x, y) ((x) * (y))",
30a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for dot(vec2, vec2)",
31a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for dot(vec3, vec3)",
32a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for dot(vec4, vec4)",
33a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com
34a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
35a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for length(vec2)",
36a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for length(vec3)",
37a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for length(vec4)",
38a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com
39a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
40a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for normalize(vec2)",
41a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for normalize(vec3)",
42a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for normalize(vec4)",
43a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com
44a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
45a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for reflect(vec2, vec2)",
46a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for reflect(vec3, vec3)",
47a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for reflect(vec4, vec4)"
48a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com};
49a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com
50a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.comconst char* kFunctionEmulationFragmentSource[] = {
51a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }",
52a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }",
53a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }",
54a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }",
55a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com
5657442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
57a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for distance(vec2, vec2)",
58a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for distance(vec3, vec3)",
59a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for distance(vec4, vec4)",
60a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com
6157442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    "#define webgl_dot_emu(x, y) ((x) * (y))",
62a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for dot(vec2, vec2)",
63a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for dot(vec3, vec3)",
64a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for dot(vec4, vec4)",
65a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com
6657442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
67a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for length(vec2)",
68a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for length(vec3)",
69a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for length(vec4)",
70a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com
7157442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
72a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for normalize(vec2)",
73a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for normalize(vec3)",
74a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for normalize(vec4)",
75a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com
7657442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
77a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for reflect(vec2, vec2)",
78a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for reflect(vec3, vec3)",
79a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    "#error no emulation for reflect(vec4, vec4)"
8032e97315e2a55557ad7c372239e0823a81243221zmo@google.com};
8132e97315e2a55557ad7c372239e0823a81243221zmo@google.com
82f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.comconst bool kFunctionEmulationVertexMask[] = {
83a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com#if defined(__APPLE__)
84a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    // Work around ATI driver bugs in Mac.
85a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionCos1
86a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionCos2
87a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionCos3
88a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionCos4
89a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    true,  // TFunctionDistance1_1
90a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDistance2_2
91a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDistance3_3
92a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDistance4_4
93a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    true,  // TFunctionDot1_1
94a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDot2_2
95a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDot3_3
96a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDot4_4
97a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    true,  // TFunctionLength1
98a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionLength2
99a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionLength3
100a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionLength4
101a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    true,  // TFunctionNormalize1
102a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionNormalize2
103a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionNormalize3
104a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionNormalize4
105a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    true,  // TFunctionReflect1_1
106a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionReflect2_2
107a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionReflect3_3
108a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionReflect4_4
109a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com#else
110a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    // Work around D3D driver bug in Win.
111f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    false, // TFunctionCos1
112f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    false, // TFunctionCos2
113f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    false, // TFunctionCos3
114f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    false, // TFunctionCos4
115a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDistance1_1
116a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDistance2_2
117a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDistance3_3
118a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDistance4_4
119a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDot1_1
120a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDot2_2
121a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDot3_3
122a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDot4_4
123a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionLength1
124a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionLength2
125a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionLength3
126a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionLength4
127a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionNormalize1
128a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionNormalize2
129a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionNormalize3
130a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionNormalize4
131a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionReflect1_1
132a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionReflect2_2
133a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionReflect3_3
134a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionReflect4_4
135a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com#endif
136f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    false  // TFunctionUnknown
137f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com};
138f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com
139f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.comconst bool kFunctionEmulationFragmentMask[] = {
140f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com#if defined(__APPLE__)
14157442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    // Work around ATI driver bugs in Mac.
142f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    true,  // TFunctionCos1
143f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    true,  // TFunctionCos2
144f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    true,  // TFunctionCos3
145f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    true,  // TFunctionCos4
14657442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    true,  // TFunctionDistance1_1
14757442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionDistance2_2
14857442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionDistance3_3
14957442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionDistance4_4
15057442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    true,  // TFunctionDot1_1
15157442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionDot2_2
15257442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionDot3_3
15357442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionDot4_4
15457442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    true,  // TFunctionLength1
15557442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionLength2
15657442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionLength3
15757442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionLength4
15857442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    true,  // TFunctionNormalize1
15957442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionNormalize2
16057442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionNormalize3
16157442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionNormalize4
16257442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    true,  // TFunctionReflect1_1
16357442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionReflect2_2
16457442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionReflect3_3
16557442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    false, // TFunctionReflect4_4
166f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com#else
16757442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com    // Work around D3D driver bug in Win.
168f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    false, // TFunctionCos1
169f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    false, // TFunctionCos2
170f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    false, // TFunctionCos3
171f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    false, // TFunctionCos4
172a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDistance1_1
173a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDistance2_2
174a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDistance3_3
175a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDistance4_4
176a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDot1_1
177a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDot2_2
178a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDot3_3
179a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionDot4_4
180a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionLength1
181a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionLength2
182a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionLength3
183a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionLength4
184a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionNormalize1
185a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionNormalize2
186a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionNormalize3
187a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionNormalize4
188a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionReflect1_1
189a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionReflect2_2
190a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionReflect3_3
191a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    false, // TFunctionReflect4_4
19257442b1107c1ed347b5901c8d9b487ac409d90dczmo@google.com#endif
193f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    false  // TFunctionUnknown
194f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com};
195f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com
19632e97315e2a55557ad7c372239e0823a81243221zmo@google.comclass BuiltInFunctionEmulationMarker : public TIntermTraverser {
19732e97315e2a55557ad7c372239e0823a81243221zmo@google.compublic:
19832e97315e2a55557ad7c372239e0823a81243221zmo@google.com    BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator)
19932e97315e2a55557ad7c372239e0823a81243221zmo@google.com        : mEmulator(emulator)
20032e97315e2a55557ad7c372239e0823a81243221zmo@google.com    {
20132e97315e2a55557ad7c372239e0823a81243221zmo@google.com    }
20232e97315e2a55557ad7c372239e0823a81243221zmo@google.com
20332e97315e2a55557ad7c372239e0823a81243221zmo@google.com    virtual bool visitUnary(Visit visit, TIntermUnary* node)
20432e97315e2a55557ad7c372239e0823a81243221zmo@google.com    {
20532e97315e2a55557ad7c372239e0823a81243221zmo@google.com        if (visit == PreVisit) {
20632e97315e2a55557ad7c372239e0823a81243221zmo@google.com            bool needToEmulate = mEmulator.SetFunctionCalled(
20732e97315e2a55557ad7c372239e0823a81243221zmo@google.com                node->getOp(), node->getOperand()->getType());
20832e97315e2a55557ad7c372239e0823a81243221zmo@google.com            if (needToEmulate)
20932e97315e2a55557ad7c372239e0823a81243221zmo@google.com                node->setUseEmulatedFunction();
21032e97315e2a55557ad7c372239e0823a81243221zmo@google.com        }
21132e97315e2a55557ad7c372239e0823a81243221zmo@google.com        return true;
21232e97315e2a55557ad7c372239e0823a81243221zmo@google.com    }
21332e97315e2a55557ad7c372239e0823a81243221zmo@google.com
214f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
215f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    {
216f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com        if (visit == PreVisit) {
217f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            // Here we handle all the built-in functions instead of the ones we
218f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            // currently identified as problematic.
219f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            switch (node->getOp()) {
220f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpLessThan:
221f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpGreaterThan:
222f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpLessThanEqual:
223f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpGreaterThanEqual:
224f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpVectorEqual:
225f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpVectorNotEqual:
226f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpMod:
227f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpPow:
228f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpAtan:
229f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpMin:
230f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpMax:
231f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpClamp:
232f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpMix:
233f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpStep:
234f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpSmoothStep:
235f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpDistance:
236f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpDot:
237f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpCross:
238f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpFaceForward:
239f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpReflect:
240f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpRefract:
241f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                case EOpMul:
242f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                    break;
243f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                default:
244f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                    return true;
245f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            };
246e40d1e9c70f1d1d5d0d92f24f8868fcf0b610639Zhenyao Mo            const TIntermSequence& sequence = *(node->getSequence());
247f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            // Right now we only handle built-in functions with two parameters.
248f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            if (sequence.size() != 2)
249f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                return true;
250f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            TIntermTyped* param1 = sequence[0]->getAsTyped();
251f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            TIntermTyped* param2 = sequence[1]->getAsTyped();
252f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            if (!param1 || !param2)
253f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                return true;
254f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            bool needToEmulate = mEmulator.SetFunctionCalled(
255f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                node->getOp(), param1->getType(), param2->getType());
256f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            if (needToEmulate)
257f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com                node->setUseEmulatedFunction();
258f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com        }
259f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com        return true;
260f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    }
261f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com
26232e97315e2a55557ad7c372239e0823a81243221zmo@google.comprivate:
26332e97315e2a55557ad7c372239e0823a81243221zmo@google.com    BuiltInFunctionEmulator& mEmulator;
26432e97315e2a55557ad7c372239e0823a81243221zmo@google.com};
26532e97315e2a55557ad7c372239e0823a81243221zmo@google.com
26632e97315e2a55557ad7c372239e0823a81243221zmo@google.com}  // anonymous namepsace
26732e97315e2a55557ad7c372239e0823a81243221zmo@google.com
268183bde5527317fa2208401e5e6b803ef51a0fdcbJamie MadillBuiltInFunctionEmulator::BuiltInFunctionEmulator(sh::GLenum shaderType)
26932e97315e2a55557ad7c372239e0823a81243221zmo@google.com{
270183bde5527317fa2208401e5e6b803ef51a0fdcbJamie Madill    if (shaderType == GL_FRAGMENT_SHADER) {
271f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com        mFunctionMask = kFunctionEmulationFragmentMask;
272a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com        mFunctionSource = kFunctionEmulationFragmentSource;
273a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    } else {
274f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com        mFunctionMask = kFunctionEmulationVertexMask;
275a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com        mFunctionSource = kFunctionEmulationVertexSource;
276a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    }
27732e97315e2a55557ad7c372239e0823a81243221zmo@google.com}
27832e97315e2a55557ad7c372239e0823a81243221zmo@google.com
27932e97315e2a55557ad7c372239e0823a81243221zmo@google.combool BuiltInFunctionEmulator::SetFunctionCalled(
280f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    TOperator op, const TType& param)
28132e97315e2a55557ad7c372239e0823a81243221zmo@google.com{
282f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    TBuiltInFunction function = IdentifyFunction(op, param);
283f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    return SetFunctionCalled(function);
284f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com}
285f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com
286f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.combool BuiltInFunctionEmulator::SetFunctionCalled(
287f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    TOperator op, const TType& param1, const TType& param2)
288f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com{
289f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    TBuiltInFunction function = IdentifyFunction(op, param1, param2);
290f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    return SetFunctionCalled(function);
291f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com}
292f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com
293f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.combool BuiltInFunctionEmulator::SetFunctionCalled(
294f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    BuiltInFunctionEmulator::TBuiltInFunction function) {
295f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    if (function == TFunctionUnknown || mFunctionMask[function] == false)
29632e97315e2a55557ad7c372239e0823a81243221zmo@google.com        return false;
29732e97315e2a55557ad7c372239e0823a81243221zmo@google.com    for (size_t i = 0; i < mFunctions.size(); ++i) {
29832e97315e2a55557ad7c372239e0823a81243221zmo@google.com        if (mFunctions[i] == function)
29932e97315e2a55557ad7c372239e0823a81243221zmo@google.com            return true;
30032e97315e2a55557ad7c372239e0823a81243221zmo@google.com    }
301a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    mFunctions.push_back(function);
302a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    return true;
30332e97315e2a55557ad7c372239e0823a81243221zmo@google.com}
30432e97315e2a55557ad7c372239e0823a81243221zmo@google.com
30532e97315e2a55557ad7c372239e0823a81243221zmo@google.comvoid BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
30632e97315e2a55557ad7c372239e0823a81243221zmo@google.com    TInfoSinkBase& out, bool withPrecision) const
30732e97315e2a55557ad7c372239e0823a81243221zmo@google.com{
30832e97315e2a55557ad7c372239e0823a81243221zmo@google.com    if (mFunctions.size() == 0)
30932e97315e2a55557ad7c372239e0823a81243221zmo@google.com        return;
31032e97315e2a55557ad7c372239e0823a81243221zmo@google.com    out << "// BEGIN: Generated code for built-in function emulation\n\n";
31132e97315e2a55557ad7c372239e0823a81243221zmo@google.com    if (withPrecision) {
312a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com        out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
31393563fcf085045a0b7c6aef0c3507c2efce599a9zmo@google.com            << "#define webgl_emu_precision highp\n"
31432e97315e2a55557ad7c372239e0823a81243221zmo@google.com            << "#else\n"
31593563fcf085045a0b7c6aef0c3507c2efce599a9zmo@google.com            << "#define webgl_emu_precision mediump\n"
31632e97315e2a55557ad7c372239e0823a81243221zmo@google.com            << "#endif\n\n";
317a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    } else {
31893563fcf085045a0b7c6aef0c3507c2efce599a9zmo@google.com        out << "#define webgl_emu_precision\n\n";
31932e97315e2a55557ad7c372239e0823a81243221zmo@google.com    }
32032e97315e2a55557ad7c372239e0823a81243221zmo@google.com    for (size_t i = 0; i < mFunctions.size(); ++i) {
321a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com        out << mFunctionSource[mFunctions[i]] << "\n\n";
32232e97315e2a55557ad7c372239e0823a81243221zmo@google.com    }
32332e97315e2a55557ad7c372239e0823a81243221zmo@google.com    out << "// END: Generated code for built-in function emulation\n\n";
32432e97315e2a55557ad7c372239e0823a81243221zmo@google.com}
32532e97315e2a55557ad7c372239e0823a81243221zmo@google.com
32632e97315e2a55557ad7c372239e0823a81243221zmo@google.comBuiltInFunctionEmulator::TBuiltInFunction
327f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.comBuiltInFunctionEmulator::IdentifyFunction(
328f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    TOperator op, const TType& param)
32932e97315e2a55557ad7c372239e0823a81243221zmo@google.com{
33009e0988466ea9f3610dfb406f859b634b8e1e188shannonwoods@chromium.org    if (param.getNominalSize() > 4 || param.getSecondarySize() > 4)
331a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com        return TFunctionUnknown;
33232e97315e2a55557ad7c372239e0823a81243221zmo@google.com    unsigned int function = TFunctionUnknown;
333f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    switch (op) {
334f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com        case EOpCos:
335f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            function = TFunctionCos1;
336f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            break;
337a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com        case EOpLength:
338a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com            function = TFunctionLength1;
339a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com            break;
340a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com        case EOpNormalize:
341a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com            function = TFunctionNormalize1;
342f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            break;
343f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com        default:
344f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            break;
345f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    }
346f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    if (function == TFunctionUnknown)
347f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com        return TFunctionUnknown;
348f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    if (param.isVector())
349f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com        function += param.getNominalSize() - 1;
350f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    return static_cast<TBuiltInFunction>(function);
351f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com}
35232e97315e2a55557ad7c372239e0823a81243221zmo@google.com
353f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.comBuiltInFunctionEmulator::TBuiltInFunction
354f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.comBuiltInFunctionEmulator::IdentifyFunction(
355f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    TOperator op, const TType& param1, const TType& param2)
356f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com{
357f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    // Right now for all the emulated functions with two parameters, the two
358f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    // parameters have the same type.
35909e0988466ea9f3610dfb406f859b634b8e1e188shannonwoods@chromium.org    if (param1.getNominalSize()     != param2.getNominalSize()   ||
36009e0988466ea9f3610dfb406f859b634b8e1e188shannonwoods@chromium.org        param1.getSecondarySize()   != param2.getSecondarySize() ||
36109e0988466ea9f3610dfb406f859b634b8e1e188shannonwoods@chromium.org        param1.getNominalSize() > 4 || param1.getSecondarySize() > 4)
362f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com        return TFunctionUnknown;
363f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com
364f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    unsigned int function = TFunctionUnknown;
365f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    switch (op) {
366a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com        case EOpDistance:
367a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com            function = TFunctionDistance1_1;
368a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com            break;
369a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com        case EOpDot:
370a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com            function = TFunctionDot1_1;
371a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com            break;
372a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com        case EOpReflect:
373a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com            function = TFunctionReflect1_1;
374f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            break;
375f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com        default:
376f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com            break;
377f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    }
378f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    if (function == TFunctionUnknown)
379f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com        return TFunctionUnknown;
380f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com    if (param1.isVector())
381f420c42442136e63c8c475446e01da1f6bcf5d32zmo@google.com        function += param1.getNominalSize() - 1;
38232e97315e2a55557ad7c372239e0823a81243221zmo@google.com    return static_cast<TBuiltInFunction>(function);
38332e97315e2a55557ad7c372239e0823a81243221zmo@google.com}
38432e97315e2a55557ad7c372239e0823a81243221zmo@google.com
38532e97315e2a55557ad7c372239e0823a81243221zmo@google.comvoid BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(
38632e97315e2a55557ad7c372239e0823a81243221zmo@google.com    TIntermNode* root)
38732e97315e2a55557ad7c372239e0823a81243221zmo@google.com{
38832e97315e2a55557ad7c372239e0823a81243221zmo@google.com    ASSERT(root);
38932e97315e2a55557ad7c372239e0823a81243221zmo@google.com
39032e97315e2a55557ad7c372239e0823a81243221zmo@google.com    BuiltInFunctionEmulationMarker marker(*this);
39132e97315e2a55557ad7c372239e0823a81243221zmo@google.com    root->traverse(&marker);
39232e97315e2a55557ad7c372239e0823a81243221zmo@google.com}
39332e97315e2a55557ad7c372239e0823a81243221zmo@google.com
394a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.comvoid BuiltInFunctionEmulator::Cleanup()
395a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com{
396a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com    mFunctions.clear();
397a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com}
398a3b4ab4c2beb1c020e474007ded4bed4a2383601zmo@google.com
39932e97315e2a55557ad7c372239e0823a81243221zmo@google.com//static
40032e97315e2a55557ad7c372239e0823a81243221zmo@google.comTString BuiltInFunctionEmulator::GetEmulatedFunctionName(
40132e97315e2a55557ad7c372239e0823a81243221zmo@google.com    const TString& name)
40232e97315e2a55557ad7c372239e0823a81243221zmo@google.com{
40332e97315e2a55557ad7c372239e0823a81243221zmo@google.com    ASSERT(name[name.length() - 1] == '(');
40432e97315e2a55557ad7c372239e0823a81243221zmo@google.com    return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
40532e97315e2a55557ad7c372239e0823a81243221zmo@google.com}
40632e97315e2a55557ad7c372239e0823a81243221zmo@google.com
407