blob: 86f67f4bcb573652e4657f5c165a15fd5c1f9f30 [file] [log] [blame]
zmo@google.com32e97312011-08-24 01:03:11 +00001//
2// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7#include "compiler/BuiltInFunctionEmulator.h"
8
9#include "compiler/SymbolTable.h"
10
11namespace {
12
13const char* kFunctionEmulationSource[] = {
14 "float webgl_normalize_emu(float a) { return normalize(a) * 1; }",
15 "vec2 webgl_normalize_emu(vec2 a) { return normalize(a) * 1; }",
16 "vec3 webgl_normalize_emu(vec3 a) { return normalize(a) * 1; }",
17 "vec4 webgl_normalize_emu(vec4 a) { return normalize(a) * 1; }",
18 "float webgl_abs_emu(float a) { float rt = abs(a); if (rt < 0.0) rt = 0.0; return rt; }",
19 "vec2 webgl_abs_emu(vec2 a) { vec2 rt = abs(a); if (rt[0] < 0.0) rt[0] = 0.0; return rt; }",
20 "vec3 webgl_abs_emu(vec3 a) { vec3 rt = abs(a); if (rt[0] < 0.0) rt[0] = 0.0; return rt; }",
21 "vec4 webgl_abs_emu(vec4 a) { vec4 rt = abs(a); if (rt[0] < 0.0) rt[0] = 0.0; return rt; }",
22 "float webgl_sign_emu(float a) { float rt = sign(a); if (rt > 1.0) rt = 1.0; return rt; }",
23 "vec2 webgl_sign_emu(vec2 a) { float rt = sign(a); if (rt[0] > 1.0) rt[0] = 1.0; return rt; }",
24 "vec3 webgl_sign_emu(vec3 a) { float rt = sign(a); if (rt[0] > 1.0) rt[0] = 1.0; return rt; }",
25 "vec4 webgl_sign_emu(vec4 a) { float rt = sign(a); if (rt[0] > 1.0) rt[0] = 1.0; return rt; }",
26};
27
28class BuiltInFunctionEmulationMarker : public TIntermTraverser {
29public:
30 BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator)
31 : mEmulator(emulator)
32 {
33 }
34
35 virtual bool visitUnary(Visit visit, TIntermUnary* node)
36 {
37 if (visit == PreVisit) {
38 bool needToEmulate = mEmulator.SetFunctionCalled(
39 node->getOp(), node->getOperand()->getType());
40 if (needToEmulate)
41 node->setUseEmulatedFunction();
42 }
43 return true;
44 }
45
46private:
47 BuiltInFunctionEmulator& mEmulator;
48};
49
50} // anonymous namepsace
51
52BuiltInFunctionEmulator::BuiltInFunctionEmulator()
53 : mFunctionGroupMask(TFunctionGroupAll)
54{
55}
56
57void BuiltInFunctionEmulator::SetFunctionGroupMask(
58 unsigned int functionGroupMask)
59{
60 mFunctionGroupMask = functionGroupMask;
61}
62
63bool BuiltInFunctionEmulator::SetFunctionCalled(
64 TOperator op, const TType& returnType)
65{
66 TBuiltInFunction function = IdentifyFunction(op, returnType);
67 if (function == TFunctionUnknown)
68 return false;
69 for (size_t i = 0; i < mFunctions.size(); ++i) {
70 if (mFunctions[i] == function)
71 return true;
72 }
73 switch (function) {
74 case TFunctionNormalize1:
75 case TFunctionNormalize2:
76 case TFunctionNormalize3:
77 case TFunctionNormalize4:
78 if (mFunctionGroupMask & TFunctionGroupNormalize) {
79 mFunctions.push_back(function);
80 return true;
81 }
82 break;
83 case TFunctionAbs1:
84 case TFunctionAbs2:
85 case TFunctionAbs3:
86 case TFunctionAbs4:
87 if (mFunctionGroupMask & TFunctionGroupAbs) {
88 mFunctions.push_back(function);
89 return true;
90 }
91 break;
92 case TFunctionSign1:
93 case TFunctionSign2:
94 case TFunctionSign3:
95 case TFunctionSign4:
96 if (mFunctionGroupMask & TFunctionGroupSign) {
97 mFunctions.push_back(function);
98 return true;
99 }
100 break;
101 default:
102 UNREACHABLE();
103 break;
104 }
105 return false;
106}
107
108void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
109 TInfoSinkBase& out, bool withPrecision) const
110{
111 if (mFunctions.size() == 0)
112 return;
113 out << "// BEGIN: Generated code for built-in function emulation\n\n";
114 if (withPrecision) {
115 out << "#if defined(GL_FRAGMENT_PRECISION_HIGH) && (GL_FRAGMENT_PRECISION_HIGH == 1)\n"
116 << "precision highp float;\n"
117 << "#else\n"
118 << "precision mediump float;\n"
119 << "#endif\n\n";
120 }
121 for (size_t i = 0; i < mFunctions.size(); ++i) {
122 out << kFunctionEmulationSource[mFunctions[i]] << "\n\n";
123 }
124 out << "// END: Generated code for built-in function emulation\n\n";
125}
126
127BuiltInFunctionEmulator::TBuiltInFunction
128BuiltInFunctionEmulator::IdentifyFunction(TOperator op, const TType& returnType)
129{
130 unsigned int function = TFunctionUnknown;
131 if (op == EOpNormalize)
132 function = TFunctionNormalize1;
133 else if (op == EOpAbs)
134 function = TFunctionAbs1;
135 else if (op == EOpSign)
136 function = TFunctionSign1;
137 else
138 return static_cast<TBuiltInFunction>(function);
139
140 if (returnType.isVector())
141 function += returnType.getNominalSize() - 1;
142 return static_cast<TBuiltInFunction>(function);
143}
144
145void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(
146 TIntermNode* root)
147{
148 ASSERT(root);
149
150 BuiltInFunctionEmulationMarker marker(*this);
151 root->traverse(&marker);
152}
153
154//static
155TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
156 const TString& name)
157{
158 ASSERT(name[name.length() - 1] == '(');
159 return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
160}
161