summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/DirectiveHandler.cpp
blob: 80b238e055b5e5e1e1885d56152d54a41055f882 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
//
// Copyright 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include "compiler/translator/DirectiveHandler.h"

#include <sstream>

#include "angle_gl.h"
#include "common/debug.h"
#include "compiler/translator/Common.h"
#include "compiler/translator/Diagnostics.h"

namespace sh
{

static TBehavior getBehavior(const std::string &str)
{
    const char kRequire[] = "require";
    const char kEnable[]  = "enable";
    const char kDisable[] = "disable";
    const char kWarn[]    = "warn";

    if (str == kRequire)
        return EBhRequire;
    else if (str == kEnable)
        return EBhEnable;
    else if (str == kDisable)
        return EBhDisable;
    else if (str == kWarn)
        return EBhWarn;
    return EBhUndefined;
}

TDirectiveHandler::TDirectiveHandler(TExtensionBehavior &extBehavior,
                                     TDiagnostics &diagnostics,
                                     int &shaderVersion,
                                     sh::GLenum shaderType)
    : mExtensionBehavior(extBehavior),
      mDiagnostics(diagnostics),
      mShaderVersion(shaderVersion),
      mShaderType(shaderType)
{}

TDirectiveHandler::~TDirectiveHandler() {}

void TDirectiveHandler::handleError(const angle::pp::SourceLocation &loc, const std::string &msg)
{
    mDiagnostics.error(loc, msg.c_str(), "");
}

void TDirectiveHandler::handlePragma(const angle::pp::SourceLocation &loc,
                                     const std::string &name,
                                     const std::string &value,
                                     bool stdgl)
{
    if (stdgl)
    {
        const char kInvariant[] = "invariant";
        const char kAll[]       = "all";

        if (name == kInvariant && value == kAll)
        {
            if (mShaderVersion == 300 && mShaderType == GL_FRAGMENT_SHADER)
            {
                // ESSL 3.00.4 section 4.6.1
                mDiagnostics.error(
                    loc, "#pragma STDGL invariant(all) can not be used in fragment shader",
                    name.c_str());
            }
            mPragma.stdgl.invariantAll = true;
        }
        // The STDGL pragma is used to reserve pragmas for use by future
        // revisions of GLSL.  Do not generate an error on unexpected
        // name and value.
        return;
    }
    else
    {
        const char kOptimize[] = "optimize";
        const char kDebug[]    = "debug";
        const char kOn[]       = "on";
        const char kOff[]      = "off";

        bool invalidValue = false;
        if (name == kOptimize)
        {
            if (value == kOn)
                mPragma.optimize = true;
            else if (value == kOff)
                mPragma.optimize = false;
            else
                invalidValue = true;
        }
        else if (name == kDebug)
        {
            if (value == kOn)
                mPragma.debug = true;
            else if (value == kOff)
                mPragma.debug = false;
            else
                invalidValue = true;
        }
        else
        {
            mDiagnostics.report(angle::pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
            return;
        }

        if (invalidValue)
        {
            mDiagnostics.error(loc, "invalid pragma value - 'on' or 'off' expected", value.c_str());
        }
    }
}

void TDirectiveHandler::handleExtension(const angle::pp::SourceLocation &loc,
                                        const std::string &name,
                                        const std::string &behavior)
{
    const char kExtAll[] = "all";

    TBehavior behaviorVal = getBehavior(behavior);
    if (behaviorVal == EBhUndefined)
    {
        mDiagnostics.error(loc, "behavior invalid", name.c_str());
        return;
    }

    if (name == kExtAll)
    {
        if (behaviorVal == EBhRequire)
        {
            mDiagnostics.error(loc, "extension cannot have 'require' behavior", name.c_str());
        }
        else if (behaviorVal == EBhEnable)
        {
            mDiagnostics.error(loc, "extension cannot have 'enable' behavior", name.c_str());
        }
        else
        {
            for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin();
                 iter != mExtensionBehavior.end(); ++iter)
                iter->second = behaviorVal;
        }
        return;
    }

    TExtensionBehavior::iterator iter = mExtensionBehavior.find(GetExtensionByName(name.c_str()));
    if (iter != mExtensionBehavior.end())
    {
        iter->second = behaviorVal;
        // OVR_multiview is implicitly enabled when OVR_multiview2 is enabled
        if (name == "GL_OVR_multiview2")
        {
            constexpr char kMultiviewExtName[] = "GL_OVR_multiview";
            iter = mExtensionBehavior.find(GetExtensionByName(kMultiviewExtName));
            if (iter != mExtensionBehavior.end())
            {
                iter->second = behaviorVal;
            }
        }
        // All the extensions listed in the spec here:
        // https://www.khronos.org/registry/OpenGL/extensions/ANDROID/ANDROID_extension_pack_es31a.txt
        // are implicitly enabled when GL_ANDROID_extension_pack_es31a is enabled
        if (name == "GL_ANDROID_extension_pack_es31a")
        {
            constexpr char kGeometryShaderExtName[]      = "GL_EXT_geometry_shader";
            constexpr char kTessellationShaderExtName[]  = "GL_EXT_tessellation_shader";
            constexpr char kGpuShader5ExtName[]          = "GL_EXT_gpu_shader5";
            constexpr char kTextureBufferExtName[]       = "GL_EXT_texture_buffer";
            constexpr char kTextureCubeMapArrayExtName[] = "GL_EXT_texture_cube_map_array";
            constexpr char kSampleVariablesExtName[]     = "GL_OES_sample_variables";
            constexpr char kShaderMultisampleInterpolationExtName[] =
                "GL_OES_shader_multisample_interpolation";
            constexpr char kShaderImageAtomicExtName[] = "GL_OES_shader_image_atomic";
            constexpr char kTextureStorageMultisample2dArrayExtName[] =
                "GL_OES_texture_storage_multisample_2d_array";
            iter = mExtensionBehavior.find(GetExtensionByName(kGeometryShaderExtName));
            if (iter != mExtensionBehavior.end())
            {
                iter->second = behaviorVal;
            }

            iter = mExtensionBehavior.find(GetExtensionByName(kTessellationShaderExtName));
            if (iter != mExtensionBehavior.end())
            {
                iter->second = behaviorVal;
            }

            iter = mExtensionBehavior.find(GetExtensionByName(kGpuShader5ExtName));
            if (iter != mExtensionBehavior.end())
            {
                iter->second = behaviorVal;
            }

            iter = mExtensionBehavior.find(GetExtensionByName(kTextureBufferExtName));
            if (iter != mExtensionBehavior.end())
            {
                iter->second = behaviorVal;
            }

            iter = mExtensionBehavior.find(GetExtensionByName(kTextureCubeMapArrayExtName));
            if (iter != mExtensionBehavior.end())
            {
                iter->second = behaviorVal;
            }

            iter = mExtensionBehavior.find(GetExtensionByName(kSampleVariablesExtName));
            if (iter != mExtensionBehavior.end())
            {
                iter->second = behaviorVal;
            }

            iter =
                mExtensionBehavior.find(GetExtensionByName(kShaderMultisampleInterpolationExtName));
            if (iter != mExtensionBehavior.end())
            {
                iter->second = behaviorVal;
            }

            iter = mExtensionBehavior.find(GetExtensionByName(kShaderImageAtomicExtName));
            if (iter != mExtensionBehavior.end())
            {
                iter->second = behaviorVal;
            }

            iter = mExtensionBehavior.find(
                GetExtensionByName(kTextureStorageMultisample2dArrayExtName));
            if (iter != mExtensionBehavior.end())
            {
                iter->second = behaviorVal;
            }
        }
        // EXT_shader_io_blocks is implicitly enabled when EXT_geometry_shader or
        // EXT_tessellation_shader is enabled.
        if (name == "GL_EXT_geometry_shader" || name == "GL_EXT_tessellation_shader")
        {
            constexpr char kIOBlocksExtName[] = "GL_EXT_shader_io_blocks";
            iter = mExtensionBehavior.find(GetExtensionByName(kIOBlocksExtName));
            if (iter != mExtensionBehavior.end())
            {
                iter->second = behaviorVal;
            }
        }
        // GL_APPLE_clip_distance is implicitly enabled when GL_EXT_clip_cull_distance is enabled
        else if (name == "GL_EXT_clip_cull_distance")
        {
            // This extension only can be enabled on greater than ESSL 300
            if (mShaderVersion < 300)
            {
                mDiagnostics.error(loc, "extension can be enabled on greater than ESSL 300",
                                   name.c_str());
                return;
            }

            constexpr char kAPPLEClipDistanceEXTName[] = "GL_APPLE_clip_distance";
            iter = mExtensionBehavior.find(GetExtensionByName(kAPPLEClipDistanceEXTName));
            if (iter != mExtensionBehavior.end())
            {
                iter->second = behaviorVal;
            }
        }
        return;
    }

    switch (behaviorVal)
    {
        case EBhRequire:
            mDiagnostics.error(loc, "extension is not supported", name.c_str());
            break;
        case EBhEnable:
        case EBhWarn:
        case EBhDisable:
            mDiagnostics.warning(loc, "extension is not supported", name.c_str());
            break;
        default:
            UNREACHABLE();
            break;
    }
}

void TDirectiveHandler::handleVersion(const angle::pp::SourceLocation &loc,
                                      int version,
                                      ShShaderSpec spec)
{
    if (((version == 100 || version == 300 || version == 310 || version == 320) &&
         !IsDesktopGLSpec(spec)) ||
        IsDesktopGLSpec(spec))
    {
        mShaderVersion = version;
    }
    else
    {
        std::stringstream stream = sh::InitializeStream<std::stringstream>();
        stream << version;
        std::string str = stream.str();
        mDiagnostics.error(loc, "client/version number not supported", str.c_str());
    }
}

}  // namespace sh