Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/angle
Path: blob/main_old/src/tests/gl_tests/BindUniformLocationTest.cpp
1693 views
1
//
2
// Copyright 2015 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
// BindUniformLocationTest.cpp : Tests of the GL_CHROMIUM_bind_uniform_location extension.
8
9
#include "test_utils/ANGLETest.h"
10
#include "test_utils/gl_raii.h"
11
12
#include <cmath>
13
14
using namespace angle;
15
16
namespace
17
{
18
19
class BindUniformLocationTest : public ANGLETest
20
{
21
protected:
22
BindUniformLocationTest()
23
{
24
setWindowWidth(128);
25
setWindowHeight(128);
26
setConfigRedBits(8);
27
setConfigGreenBits(8);
28
setConfigBlueBits(8);
29
setConfigAlphaBits(8);
30
}
31
32
void testTearDown() override
33
{
34
if (mProgram != 0)
35
{
36
glDeleteProgram(mProgram);
37
}
38
}
39
40
GLuint mProgram = 0;
41
};
42
43
// Test basic functionality of GL_CHROMIUM_bind_uniform_location
44
TEST_P(BindUniformLocationTest, Basic)
45
{
46
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
47
48
constexpr char kFS[] = R"(precision mediump float;
49
uniform vec4 u_colorC;
50
uniform vec4 u_colorB[2];
51
uniform vec4 u_colorA;
52
void main()
53
{
54
gl_FragColor = u_colorA + u_colorB[0] + u_colorB[1] + u_colorC;
55
})";
56
57
GLint colorALocation = 3;
58
GLint colorBLocation = 10;
59
GLint colorCLocation = 5;
60
61
mProgram = CompileProgram(essl1_shaders::vs::Simple(), kFS, [&](GLuint program) {
62
glBindUniformLocationCHROMIUM(program, colorALocation, "u_colorA");
63
glBindUniformLocationCHROMIUM(program, colorBLocation, "u_colorB[0]");
64
glBindUniformLocationCHROMIUM(program, colorCLocation, "u_colorC");
65
});
66
ASSERT_NE(0u, mProgram);
67
68
glUseProgram(mProgram);
69
70
static const float colorB[] = {
71
0.0f, 0.50f, 0.0f, 0.0f, 0.0f, 0.0f, 0.75f, 0.0f,
72
};
73
74
glUniform4f(colorALocation, 0.25f, 0.0f, 0.0f, 0.0f);
75
glUniform4fv(colorBLocation, 2, colorB);
76
glUniform4f(colorCLocation, 0.0f, 0.0f, 0.0f, 1.0f);
77
78
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
79
80
EXPECT_GL_NO_ERROR();
81
EXPECT_PIXEL_NEAR(0, 0, 64, 128, 192, 255, 1.0);
82
}
83
84
// Force a sampler location and make sure it samples the correct texture
85
TEST_P(BindUniformLocationTest, SamplerLocation)
86
{
87
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
88
89
constexpr char kFS[] = R"(precision mediump float;
90
uniform vec4 u_colorA;
91
uniform vec4 u_colorB[2];
92
uniform sampler2D u_sampler;
93
void main()
94
{
95
gl_FragColor = u_colorA + u_colorB[0] + u_colorB[1] + texture2D(u_sampler, vec2(0, 0));
96
})";
97
98
GLint colorALocation = 3;
99
GLint colorBLocation = 10;
100
GLint samplerLocation = 1;
101
102
mProgram = CompileProgram(essl1_shaders::vs::Simple(), kFS, [&](GLuint program) {
103
glBindUniformLocationCHROMIUM(program, colorALocation, "u_colorA");
104
glBindUniformLocationCHROMIUM(program, colorBLocation, "u_colorB[0]");
105
glBindUniformLocationCHROMIUM(program, samplerLocation, "u_sampler");
106
});
107
ASSERT_NE(0u, mProgram);
108
109
glUseProgram(mProgram);
110
111
static const float colorB[] = {
112
0.0f, 0.50f, 0.0f, 0.0f, 0.0f, 0.0f, 0.75f, 0.0f,
113
};
114
115
glUniform4f(colorALocation, 0.25f, 0.0f, 0.0f, 0.0f);
116
glUniform4fv(colorBLocation, 2, colorB);
117
118
// Point the texture at texture unit 2
119
glUniform1i(samplerLocation, 2);
120
121
GLTexture texture;
122
glActiveTexture(GL_TEXTURE2);
123
glBindTexture(GL_TEXTURE_2D, texture);
124
constexpr GLubyte kTextureData[] = {32, 32, 32, 255};
125
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, kTextureData);
126
127
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
128
129
EXPECT_GL_NO_ERROR();
130
EXPECT_PIXEL_NEAR(0, 0, 96, 160, 224, 255, 1.0);
131
}
132
133
// Test that conflicts are detected when two uniforms are bound to the same location
134
TEST_P(BindUniformLocationTest, ConflictsDetection)
135
{
136
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
137
138
constexpr char kFS[] =
139
R"(precision mediump float;
140
uniform vec4 u_colorA;
141
uniform vec4 u_colorB;
142
void main()
143
{
144
gl_FragColor = u_colorA + u_colorB;
145
})";
146
147
GLint colorALocation = 3;
148
GLint colorBLocation = 4;
149
150
GLuint vs = CompileShader(GL_VERTEX_SHADER, essl1_shaders::vs::Simple());
151
GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
152
153
mProgram = glCreateProgram();
154
glAttachShader(mProgram, vs);
155
glDeleteShader(vs);
156
glAttachShader(mProgram, fs);
157
glDeleteShader(fs);
158
159
glBindUniformLocationCHROMIUM(mProgram, colorALocation, "u_colorA");
160
// Bind u_colorB to location a, causing conflicts, link should fail.
161
glBindUniformLocationCHROMIUM(mProgram, colorALocation, "u_colorB");
162
glLinkProgram(mProgram);
163
GLint linked = 0;
164
glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
165
ASSERT_EQ(0, linked);
166
167
// Bind u_colorB to location b, no conflicts, link should succeed.
168
glBindUniformLocationCHROMIUM(mProgram, colorBLocation, "u_colorB");
169
glLinkProgram(mProgram);
170
linked = 0;
171
glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
172
EXPECT_EQ(1, linked);
173
}
174
175
// Test a use case of the chromium compositor
176
TEST_P(BindUniformLocationTest, Compositor)
177
{
178
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
179
180
constexpr char kVS[] =
181
R"(attribute vec4 a_position;
182
attribute vec2 a_texCoord;
183
uniform mat4 matrix;
184
uniform vec2 color_a[4];
185
uniform vec4 color_b;
186
varying vec4 v_color;
187
void main()
188
{
189
v_color.xy = color_a[0] + color_a[1];
190
v_color.zw = color_a[2] + color_a[3];
191
v_color += color_b;
192
gl_Position = matrix * a_position;
193
})";
194
195
constexpr char kFS[] =
196
R"(precision mediump float;
197
varying vec4 v_color;
198
uniform float alpha;
199
uniform vec4 multiplier;
200
uniform vec3 color_c[8];
201
void main()
202
{
203
vec4 color_c_sum = vec4(0.0);
204
color_c_sum.xyz += color_c[0];
205
color_c_sum.xyz += color_c[1];
206
color_c_sum.xyz += color_c[2];
207
color_c_sum.xyz += color_c[3];
208
color_c_sum.xyz += color_c[4];
209
color_c_sum.xyz += color_c[5];
210
color_c_sum.xyz += color_c[6];
211
color_c_sum.xyz += color_c[7];
212
color_c_sum.w = alpha;
213
color_c_sum *= multiplier;
214
gl_FragColor = v_color + color_c_sum;
215
})";
216
217
int counter = 6;
218
int matrixLocation = counter++;
219
int colorALocation = counter++;
220
int colorBLocation = counter++;
221
int alphaLocation = counter++;
222
int multiplierLocation = counter++;
223
int colorCLocation = counter++;
224
225
mProgram = CompileProgram(kVS, kFS, [&](GLuint program) {
226
glBindUniformLocationCHROMIUM(program, matrixLocation, "matrix");
227
glBindUniformLocationCHROMIUM(program, colorALocation, "color_a");
228
glBindUniformLocationCHROMIUM(program, colorBLocation, "color_b");
229
glBindUniformLocationCHROMIUM(program, alphaLocation, "alpha");
230
glBindUniformLocationCHROMIUM(program, multiplierLocation, "multiplier");
231
glBindUniformLocationCHROMIUM(program, colorCLocation, "color_c");
232
});
233
ASSERT_NE(0u, mProgram);
234
235
glUseProgram(mProgram);
236
237
static const float colorA[] = {
238
0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f,
239
};
240
241
static const float colorC[] = {
242
0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f,
243
0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f,
244
};
245
246
static const float identity[] = {
247
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
248
};
249
250
glUniformMatrix4fv(matrixLocation, 1, false, identity);
251
glUniform2fv(colorALocation, 4, colorA);
252
glUniform4f(colorBLocation, 0.2f, 0.2f, 0.2f, 0.2f);
253
glUniform1f(alphaLocation, 0.8f);
254
glUniform4f(multiplierLocation, 0.5f, 0.5f, 0.5f, 0.5f);
255
glUniform3fv(colorCLocation, 8, colorC);
256
257
glDrawArrays(GL_TRIANGLES, 0, 6);
258
259
drawQuad(mProgram, "a_position", 0.5f);
260
261
EXPECT_PIXEL_EQ(0, 0, 204, 204, 204, 204);
262
}
263
264
// Test that unused uniforms don't conflict when bound to the same location
265
TEST_P(BindUniformLocationTest, UnusedUniformUpdate)
266
{
267
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
268
269
ASSERT_NE(nullptr, glBindUniformLocationCHROMIUM);
270
271
constexpr char kFS[] = R"(precision mediump float;
272
uniform vec4 u_colorA;
273
uniform float u_colorU;
274
uniform vec4 u_colorC;
275
void main()
276
{
277
gl_FragColor = u_colorA + u_colorC;
278
})";
279
280
const GLint colorULocation = 1;
281
const GLint nonexistingLocation = 5;
282
const GLint unboundLocation = 6;
283
284
mProgram = CompileProgram(essl1_shaders::vs::Simple(), kFS, [&](GLuint program) {
285
glBindUniformLocationCHROMIUM(program, colorULocation, "u_colorU");
286
// The non-existing uniform should behave like existing, but optimized away
287
// uniform.
288
glBindUniformLocationCHROMIUM(program, nonexistingLocation, "nonexisting");
289
// Let A and C be assigned automatic locations.
290
});
291
ASSERT_NE(0u, mProgram);
292
293
glUseProgram(mProgram);
294
295
// No errors on bound locations, since caller does not know
296
// if the driver optimizes them away or not.
297
glUniform1f(colorULocation, 0.25f);
298
EXPECT_GL_NO_ERROR();
299
300
// No errors on bound locations of names that do not exist
301
// in the shader. Otherwise it would be inconsistent wrt the
302
// optimization case.
303
glUniform1f(nonexistingLocation, 0.25f);
304
EXPECT_GL_NO_ERROR();
305
306
// The above are equal to updating -1.
307
glUniform1f(-1, 0.25f);
308
EXPECT_GL_NO_ERROR();
309
310
// No errors when updating with other type either.
311
// The type can not be known with the non-existing case.
312
glUniform2f(colorULocation, 0.25f, 0.25f);
313
EXPECT_GL_NO_ERROR();
314
glUniform2f(nonexistingLocation, 0.25f, 0.25f);
315
EXPECT_GL_NO_ERROR();
316
glUniform2f(-1, 0.25f, 0.25f);
317
EXPECT_GL_NO_ERROR();
318
319
// Ensure that driver or ANGLE has optimized the variable
320
// away and the test tests what it is supposed to.
321
EXPECT_EQ(-1, glGetUniformLocation(mProgram, "u_colorU"));
322
323
// The bound location gets marked as used and the driver
324
// does not allocate other variables to that location.
325
EXPECT_NE(colorULocation, glGetUniformLocation(mProgram, "u_colorA"));
326
EXPECT_NE(colorULocation, glGetUniformLocation(mProgram, "u_colorC"));
327
EXPECT_NE(nonexistingLocation, glGetUniformLocation(mProgram, "u_colorA"));
328
EXPECT_NE(nonexistingLocation, glGetUniformLocation(mProgram, "u_colorC"));
329
330
// Unintuitive: while specifying value works, getting the value does not.
331
GLfloat getResult = 0.0f;
332
glGetUniformfv(mProgram, colorULocation, &getResult);
333
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
334
glGetUniformfv(mProgram, nonexistingLocation, &getResult);
335
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
336
glGetUniformfv(mProgram, -1, &getResult);
337
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
338
339
// Updating an unbound, non-existing location still causes
340
// an error.
341
glUniform1f(unboundLocation, 0.25f);
342
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
343
}
344
345
// GL backend optimizes away a uniform in the vertex shader if it's only used to
346
// compute a varying that is never referenced in the fragment shader.
347
TEST_P(BindUniformLocationTest, UnusedUniformUpdateComplex)
348
{
349
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
350
351
ASSERT_NE(nullptr, glBindUniformLocationCHROMIUM);
352
353
constexpr char kVS[] = R"(precision highp float;
354
attribute vec4 a_position;
355
varying vec4 v_unused;
356
uniform vec4 u_unused;
357
void main()
358
{
359
gl_Position = a_position;
360
v_unused = u_unused;
361
}
362
)";
363
364
constexpr char kFS[] = R"(precision mediump float;
365
varying vec4 v_unused;
366
void main()
367
{
368
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
369
})";
370
371
const GLint unusedLocation = 1;
372
373
mProgram = CompileProgram(kVS, kFS, [&](GLuint program) {
374
glBindUniformLocationCHROMIUM(program, unusedLocation, "u_unused");
375
});
376
ASSERT_NE(0u, mProgram);
377
378
glUseProgram(mProgram);
379
380
// No errors on bound locations of names that do not exist
381
// in the shader. Otherwise it would be inconsistent wrt the
382
// optimization case.
383
glUniform4f(unusedLocation, 0.25f, 0.25f, 0.25f, 0.25f);
384
EXPECT_GL_NO_ERROR();
385
}
386
387
// Test for a bug where using a sampler caused GL error if the mProgram had
388
// uniforms that were optimized away by the driver. This was only a problem with
389
// glBindUniformLocationCHROMIUM implementation. This could be reproed by
390
// binding the sampler to a location higher than the amount of active uniforms.
391
TEST_P(BindUniformLocationTest, UseSamplerWhenUnusedUniforms)
392
{
393
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
394
395
constexpr char kFS[] =
396
R"(uniform sampler2D tex;
397
void main()
398
{
399
gl_FragColor = texture2D(tex, vec2(1));
400
})";
401
402
const GLuint texLocation = 54;
403
404
mProgram = CompileProgram(essl1_shaders::vs::Simple(), kFS, [&](GLuint program) {
405
glBindUniformLocationCHROMIUM(program, texLocation, "tex");
406
});
407
ASSERT_NE(0u, mProgram);
408
409
glUseProgram(mProgram);
410
glUniform1i(texLocation, 0);
411
EXPECT_GL_NO_ERROR();
412
}
413
414
// Test for binding a statically used uniform to the same location as a non-statically used uniform.
415
// This is valid according to the extension spec.
416
TEST_P(BindUniformLocationTest, SameLocationForUsedAndUnusedUniform)
417
{
418
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
419
420
constexpr char kFS[] =
421
R"(precision mediump float;
422
uniform vec4 a;
423
uniform vec4 b;
424
void main()
425
{
426
gl_FragColor = a;
427
})";
428
429
const GLuint location = 54;
430
431
mProgram = CompileProgram(essl1_shaders::vs::Zero(), kFS, [&](GLuint program) {
432
glBindUniformLocationCHROMIUM(program, location, "a");
433
glBindUniformLocationCHROMIUM(program, location, "b");
434
});
435
ASSERT_NE(0u, mProgram);
436
437
glUseProgram(mProgram);
438
glUniform4f(location, 0.0, 1.0, 0.0, 1.0);
439
EXPECT_GL_NO_ERROR();
440
}
441
442
class BindUniformLocationES31Test : public BindUniformLocationTest
443
{
444
protected:
445
BindUniformLocationES31Test() : BindUniformLocationTest() {}
446
447
void linkProgramWithUniformLocation(const char *vs,
448
const char *fs,
449
const char *uniformName,
450
GLint uniformLocation)
451
{
452
mProgram = CompileProgram(vs, fs, [&](GLuint program) {
453
glBindUniformLocationCHROMIUM(program, uniformLocation, uniformName);
454
});
455
}
456
};
457
458
// Test for when the shader specifies an explicit uniform location with a layout qualifier and the
459
// bindUniformLocation API sets a consistent location.
460
TEST_P(BindUniformLocationES31Test, ConsistentWithLocationLayoutQualifier)
461
{
462
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
463
464
constexpr char kFS[] =
465
"#version 310 es\n"
466
"uniform layout(location=2) highp sampler2D tex;\n"
467
"out highp vec4 my_FragColor;\n"
468
"void main()\n"
469
"{\n"
470
" my_FragColor = texture(tex, vec2(1));\n"
471
"}\n";
472
473
const GLuint texLocation = 2;
474
475
linkProgramWithUniformLocation(essl31_shaders::vs::Zero(), kFS, "tex", texLocation);
476
477
GLint linked = GL_FALSE;
478
glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
479
ASSERT_GL_TRUE(linked);
480
481
EXPECT_EQ(static_cast<GLint>(texLocation), glGetUniformLocation(mProgram, "tex"));
482
glUseProgram(mProgram);
483
glUniform1i(texLocation, 0);
484
EXPECT_GL_NO_ERROR();
485
}
486
487
// Test for when the shader specifies an explicit uniform location with a layout qualifier and the
488
// bindUniformLocation API sets a conflicting location for the same variable. The shader-set
489
// location should prevail.
490
TEST_P(BindUniformLocationES31Test, LocationLayoutQualifierOverridesAPIBinding)
491
{
492
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
493
494
constexpr char kFS[] =
495
"#version 310 es\n"
496
"uniform layout(location=2) highp sampler2D tex;\n"
497
"out highp vec4 my_FragColor;\n"
498
"void main()\n"
499
"{\n"
500
" my_FragColor = texture(tex, vec2(1));\n"
501
"}\n";
502
503
const GLuint shaderTexLocation = 2;
504
const GLuint texLocation = 3;
505
506
linkProgramWithUniformLocation(essl31_shaders::vs::Zero(), kFS, "tex", texLocation);
507
508
GLint linked = GL_FALSE;
509
glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
510
ASSERT_GL_TRUE(linked);
511
512
EXPECT_EQ(static_cast<GLint>(shaderTexLocation), glGetUniformLocation(mProgram, "tex"));
513
glUseProgram(mProgram);
514
glUniform1i(shaderTexLocation, 1);
515
EXPECT_GL_NO_ERROR();
516
glUniform1i(texLocation, 2);
517
EXPECT_GL_NO_ERROR();
518
}
519
520
// Test for when the shader specifies an explicit uniform location with a layout qualifier and the
521
// bindUniformLocation API sets a conflicting location for a different variable. Linking should
522
// fail.
523
TEST_P(BindUniformLocationES31Test, LocationLayoutQualifierConflictsWithAPIBinding)
524
{
525
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
526
527
constexpr char kFS[] =
528
"#version 310 es\n"
529
"uniform layout(location=2) highp sampler2D tex;\n"
530
"uniform highp sampler2D tex2;\n"
531
"out highp vec4 my_FragColor;\n"
532
"void main()\n"
533
"{\n"
534
" my_FragColor = texture(tex2, vec2(1));\n"
535
"}\n";
536
537
const GLuint tex2Location = 2;
538
539
linkProgramWithUniformLocation(essl31_shaders::vs::Zero(), kFS, "tex2", tex2Location);
540
541
GLint linked = GL_FALSE;
542
glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
543
ASSERT_GL_FALSE(linked);
544
}
545
546
// Test for binding a location for an array of arrays uniform.
547
TEST_P(BindUniformLocationES31Test, ArrayOfArrays)
548
{
549
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_CHROMIUM_bind_uniform_location"));
550
551
constexpr char kFS[] =
552
R"(#version 310 es
553
precision highp float;
554
uniform vec4 sourceColor[2][1];
555
out highp vec4 my_FragColor;
556
void main()
557
{
558
my_FragColor = sourceColor[1][0];
559
})";
560
561
const GLuint location = 8;
562
563
linkProgramWithUniformLocation(essl31_shaders::vs::Simple(), kFS, "sourceColor[1]", location);
564
565
GLint linked = GL_FALSE;
566
glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
567
ASSERT_GL_TRUE(linked);
568
569
glUseProgram(mProgram);
570
glUniform4f(location, 0.0f, 1.0f, 0.0f, 1.0f);
571
572
drawQuad(mProgram, essl31_shaders::PositionAttrib(), 0.5f);
573
EXPECT_GL_NO_ERROR();
574
575
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
576
}
577
578
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
579
// tests should be run against.
580
ANGLE_INSTANTIATE_TEST_ES2(BindUniformLocationTest);
581
582
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BindUniformLocationES31Test);
583
ANGLE_INSTANTIATE_TEST_ES31(BindUniformLocationES31Test);
584
585
} // namespace
586
587