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 #include "test_utils/ANGLETest.h"
8 #include "test_utils/gl_raii.h"
9
10 using namespace angle;
11
12 namespace
13 {
14
15 class UniformBufferTest : public ANGLETest
16 {
17 protected:
UniformBufferTest()18 UniformBufferTest()
19 {
20 setWindowWidth(128);
21 setWindowHeight(128);
22 setConfigRedBits(8);
23 setConfigGreenBits(8);
24 setConfigBlueBits(8);
25 setConfigAlphaBits(8);
26 }
27
SetUp()28 void SetUp() override
29 {
30 ANGLETest::SetUp();
31
32 const std::string vertexShaderSource = SHADER_SOURCE
33 ( #version 300 es\n
34 in vec4 position;
35 void main()
36 {
37 gl_Position = position;
38 }
39 );
40 const std::string fragmentShaderSource = SHADER_SOURCE
41 ( #version 300 es\n
42 precision highp float;
43 uniform uni {
44 vec4 color;
45 };
46
47 out vec4 fragColor;
48
49 void main()
50 {
51 fragColor = color;
52 }
53 );
54
55 mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
56 ASSERT_NE(mProgram, 0u);
57
58 mUniformBufferIndex = glGetUniformBlockIndex(mProgram, "uni");
59 ASSERT_NE(mUniformBufferIndex, -1);
60
61 glGenBuffers(1, &mUniformBuffer);
62
63 ASSERT_GL_NO_ERROR();
64 }
65
TearDown()66 void TearDown() override
67 {
68 glDeleteBuffers(1, &mUniformBuffer);
69 glDeleteProgram(mProgram);
70 ANGLETest::TearDown();
71 }
72
73 GLuint mProgram;
74 GLint mUniformBufferIndex;
75 GLuint mUniformBuffer;
76 };
77
78 // Basic UBO functionality.
TEST_P(UniformBufferTest,Simple)79 TEST_P(UniformBufferTest, Simple)
80 {
81 glClear(GL_COLOR_BUFFER_BIT);
82 float floatData[4] = {0.5f, 0.75f, 0.25f, 1.0f};
83
84 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
85 glBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 4, floatData, GL_STATIC_DRAW);
86
87 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
88
89 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
90 drawQuad(mProgram, "position", 0.5f);
91
92 ASSERT_GL_NO_ERROR();
93 EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
94 }
95
96 // Test that using a UBO with a non-zero offset and size actually works.
97 // The first step of this test renders a color from a UBO with a zero offset.
98 // The second step renders a color from a UBO with a non-zero offset.
TEST_P(UniformBufferTest,UniformBufferRange)99 TEST_P(UniformBufferTest, UniformBufferRange)
100 {
101 int px = getWindowWidth() / 2;
102 int py = getWindowHeight() / 2;
103
104 // Query the uniform buffer alignment requirement
105 GLint alignment;
106 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
107
108 GLint64 maxUniformBlockSize;
109 glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
110 if (alignment >= maxUniformBlockSize)
111 {
112 // ANGLE doesn't implement UBO offsets for this platform.
113 // Ignore the test case.
114 return;
115 }
116
117 ASSERT_GL_NO_ERROR();
118
119 // Let's create a buffer which contains two vec4.
120 GLuint vec4Size = 4 * sizeof(float);
121 GLuint stride = 0;
122 do
123 {
124 stride += alignment;
125 }
126 while (stride < vec4Size);
127
128 std::vector<char> v(2 * stride);
129 float *first = reinterpret_cast<float*>(v.data());
130 float *second = reinterpret_cast<float*>(v.data() + stride);
131
132 first[0] = 10.f / 255.f;
133 first[1] = 20.f / 255.f;
134 first[2] = 30.f / 255.f;
135 first[3] = 40.f / 255.f;
136
137 second[0] = 110.f / 255.f;
138 second[1] = 120.f / 255.f;
139 second[2] = 130.f / 255.f;
140 second[3] = 140.f / 255.f;
141
142 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
143 // We use on purpose a size which is not a multiple of the alignment.
144 glBufferData(GL_UNIFORM_BUFFER, stride + vec4Size, v.data(), GL_STATIC_DRAW);
145
146 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
147
148 EXPECT_GL_NO_ERROR();
149
150 // Bind the first part of the uniform buffer and draw
151 // Use a size which is smaller than the alignment to check
152 // to check that this case is handle correctly in the conversion to 11.1.
153 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, 0, vec4Size);
154 drawQuad(mProgram, "position", 0.5f);
155 EXPECT_GL_NO_ERROR();
156 EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
157
158 // Bind the second part of the uniform buffer and draw
159 // Furthermore the D3D11.1 backend will internally round the vec4Size (16 bytes) to a stride (256 bytes)
160 // hence it will try to map the range [stride, 2 * stride] which is
161 // out-of-bound of the buffer bufferSize = stride + vec4Size < 2 * stride.
162 // Ensure that this behaviour works.
163 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, stride, vec4Size);
164 drawQuad(mProgram, "position", 0.5f);
165 EXPECT_GL_NO_ERROR();
166 EXPECT_PIXEL_EQ(px, py, 110, 120, 130, 140);
167 }
168
169 // Test uniform block bindings.
TEST_P(UniformBufferTest,UniformBufferBindings)170 TEST_P(UniformBufferTest, UniformBufferBindings)
171 {
172 int px = getWindowWidth() / 2;
173 int py = getWindowHeight() / 2;
174
175 ASSERT_GL_NO_ERROR();
176
177 // Let's create a buffer which contains one vec4.
178 GLuint vec4Size = 4 * sizeof(float);
179 std::vector<char> v(vec4Size);
180 float *first = reinterpret_cast<float*>(v.data());
181
182 first[0] = 10.f / 255.f;
183 first[1] = 20.f / 255.f;
184 first[2] = 30.f / 255.f;
185 first[3] = 40.f / 255.f;
186
187 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
188 glBufferData(GL_UNIFORM_BUFFER, vec4Size, v.data(), GL_STATIC_DRAW);
189
190 EXPECT_GL_NO_ERROR();
191
192 // Try to bind the buffer to binding point 2
193 glUniformBlockBinding(mProgram, mUniformBufferIndex, 2);
194 glBindBufferBase(GL_UNIFORM_BUFFER, 2, mUniformBuffer);
195 drawQuad(mProgram, "position", 0.5f);
196 EXPECT_GL_NO_ERROR();
197 EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
198
199 // Clear the framebuffer
200 glClearColor(0.0, 0.0, 0.0, 0.0);
201 glClear(GL_COLOR_BUFFER_BIT);
202 EXPECT_PIXEL_EQ(px, py, 0, 0, 0, 0);
203
204 // Try to bind the buffer to another binding point
205 glUniformBlockBinding(mProgram, mUniformBufferIndex, 5);
206 glBindBufferBase(GL_UNIFORM_BUFFER, 5, mUniformBuffer);
207 drawQuad(mProgram, "position", 0.5f);
208 EXPECT_GL_NO_ERROR();
209 EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
210 }
211
212 // Test that ANGLE handles used but unbound UBO.
213 // TODO: A test case shouldn't depend on the error code of an undefined behaviour. Move this to unit tests of the validation layer.
TEST_P(UniformBufferTest,UnboundUniformBuffer)214 TEST_P(UniformBufferTest, UnboundUniformBuffer)
215 {
216 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
217 glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0);
218 EXPECT_GL_NO_ERROR();
219
220 drawQuad(mProgram, "position", 0.5f);
221 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
222 }
223
224 // Update a UBO many time and verify that ANGLE uses the latest version of the data.
225 // https://code.google.com/p/angleproject/issues/detail?id=965
TEST_P(UniformBufferTest,UniformBufferManyUpdates)226 TEST_P(UniformBufferTest, UniformBufferManyUpdates)
227 {
228 // TODO(jmadill): Figure out why this fails on Intel OpenGL.
229 if (IsIntel() && IsOpenGL())
230 {
231 std::cout << "Test skipped on Intel OpenGL." << std::endl;
232 return;
233 }
234
235 int px = getWindowWidth() / 2;
236 int py = getWindowHeight() / 2;
237
238 ASSERT_GL_NO_ERROR();
239
240 float data[4];
241
242 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
243 glBufferData(GL_UNIFORM_BUFFER, sizeof(data), NULL, GL_DYNAMIC_DRAW);
244 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
245 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
246
247 EXPECT_GL_NO_ERROR();
248
249 // Repeteadly update the data and draw
250 for (size_t i = 0; i < 10; ++i)
251 {
252 data[0] = (i + 10.f) / 255.f;
253 data[1] = (i + 20.f) / 255.f;
254 data[2] = (i + 30.f) / 255.f;
255 data[3] = (i + 40.f) / 255.f;
256
257 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(data), data);
258
259 drawQuad(mProgram, "position", 0.5f);
260 EXPECT_GL_NO_ERROR();
261 EXPECT_PIXEL_EQ(px, py, i + 10, i + 20, i + 30, i + 40);
262 }
263 }
264
265 // Use a large number of buffer ranges (compared to the actual size of the UBO)
TEST_P(UniformBufferTest,ManyUniformBufferRange)266 TEST_P(UniformBufferTest, ManyUniformBufferRange)
267 {
268 int px = getWindowWidth() / 2;
269 int py = getWindowHeight() / 2;
270
271 // Query the uniform buffer alignment requirement
272 GLint alignment;
273 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
274
275 GLint64 maxUniformBlockSize;
276 glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
277 if (alignment >= maxUniformBlockSize)
278 {
279 // ANGLE doesn't implement UBO offsets for this platform.
280 // Ignore the test case.
281 return;
282 }
283
284 ASSERT_GL_NO_ERROR();
285
286 // Let's create a buffer which contains eight vec4.
287 GLuint vec4Size = 4 * sizeof(float);
288 GLuint stride = 0;
289 do
290 {
291 stride += alignment;
292 }
293 while (stride < vec4Size);
294
295 std::vector<char> v(8 * stride);
296
297 for (size_t i = 0; i < 8; ++i)
298 {
299 float *data = reinterpret_cast<float*>(v.data() + i * stride);
300
301 data[0] = (i + 10.f) / 255.f;
302 data[1] = (i + 20.f) / 255.f;
303 data[2] = (i + 30.f) / 255.f;
304 data[3] = (i + 40.f) / 255.f;
305 }
306
307 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
308 glBufferData(GL_UNIFORM_BUFFER, v.size(), v.data(), GL_STATIC_DRAW);
309
310 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
311
312 EXPECT_GL_NO_ERROR();
313
314 // Bind each possible offset
315 for (size_t i = 0; i < 8; ++i)
316 {
317 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, i * stride, stride);
318 drawQuad(mProgram, "position", 0.5f);
319 EXPECT_GL_NO_ERROR();
320 EXPECT_PIXEL_EQ(px, py, 10 + i, 20 + i, 30 + i, 40 + i);
321 }
322
323 // Try to bind larger range
324 for (size_t i = 0; i < 7; ++i)
325 {
326 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, i * stride, 2 * stride);
327 drawQuad(mProgram, "position", 0.5f);
328 EXPECT_GL_NO_ERROR();
329 EXPECT_PIXEL_EQ(px, py, 10 + i, 20 + i, 30 + i, 40 + i);
330 }
331
332 // Try to bind even larger range
333 for (size_t i = 0; i < 5; ++i)
334 {
335 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, i * stride, 4 * stride);
336 drawQuad(mProgram, "position", 0.5f);
337 EXPECT_GL_NO_ERROR();
338 EXPECT_PIXEL_EQ(px, py, 10 + i, 20 + i, 30 + i, 40 + i);
339 }
340 }
341
342 // Tests that active uniforms have the right names.
TEST_P(UniformBufferTest,ActiveUniformNames)343 TEST_P(UniformBufferTest, ActiveUniformNames)
344 {
345 const std::string &vertexShaderSource =
346 "#version 300 es\n"
347 "in vec2 position;\n"
348 "out vec2 v;\n"
349 "uniform blockName1 {\n"
350 " float f1;\n"
351 "} instanceName1;\n"
352 "uniform blockName2 {\n"
353 " float f2;\n"
354 "} instanceName2[1];\n"
355 "void main() {\n"
356 " v = vec2(instanceName1.f1, instanceName2[0].f2);\n"
357 " gl_Position = vec4(position, 0, 1);\n"
358 "}";
359
360 const std::string &fragmentShaderSource =
361 "#version 300 es\n"
362 "precision highp float;\n"
363 "in vec2 v;\n"
364 "out vec4 color;\n"
365 "void main() {\n"
366 " color = vec4(v, 0, 1);\n"
367 "}";
368
369 GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
370 ASSERT_NE(0u, program);
371
372 GLint activeUniformBlocks;
373 glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &activeUniformBlocks);
374 ASSERT_EQ(2, activeUniformBlocks);
375
376 GLint maxLength;
377 GLsizei length;
378 glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxLength);
379 std::vector<GLchar> strBlockNameBuffer(maxLength + 1, 0);
380 glGetActiveUniformBlockName(program, 0, maxLength, &length, &strBlockNameBuffer[0]);
381 ASSERT_GL_NO_ERROR();
382 EXPECT_EQ("blockName1", std::string(&strBlockNameBuffer[0]));
383
384 glGetActiveUniformBlockName(program, 1, maxLength, &length, &strBlockNameBuffer[0]);
385 ASSERT_GL_NO_ERROR();
386 EXPECT_EQ("blockName2[0]", std::string(&strBlockNameBuffer[0]));
387
388 GLint activeUniforms;
389 glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &activeUniforms);
390
391 ASSERT_EQ(2, activeUniforms);
392
393 GLint size;
394 GLenum type;
395 glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
396 std::vector<GLchar> strUniformNameBuffer(maxLength + 1, 0);
397 glGetActiveUniform(program, 0, maxLength, &length, &size, &type, &strUniformNameBuffer[0]);
398
399 ASSERT_GL_NO_ERROR();
400 EXPECT_EQ(1, size);
401 EXPECT_GLENUM_EQ(GL_FLOAT, type);
402 EXPECT_EQ("blockName1.f1", std::string(&strUniformNameBuffer[0]));
403
404 glGetActiveUniform(program, 1, maxLength, &length, &size, &type, &strUniformNameBuffer[0]);
405
406 ASSERT_GL_NO_ERROR();
407 EXPECT_EQ(1, size);
408 EXPECT_GLENUM_EQ(GL_FLOAT, type);
409 EXPECT_EQ("blockName2.f2", std::string(&strUniformNameBuffer[0]));
410 }
411
412 // Tests active uniforms and blocks when the layout is std140, shared and packed.
TEST_P(UniformBufferTest,ActiveUniformNumberAndName)413 TEST_P(UniformBufferTest, ActiveUniformNumberAndName)
414 {
415 // TODO(Jiajia): Figure out why this fails on Intel on Mac.
416 // This case can pass on Intel Mac-10.11/10.12. But it fails on Intel Mac-10.10.
417 if (IsIntel() && IsOSX())
418 {
419 std::cout << "Test skipped on Intel on Mac." << std::endl;
420 return;
421 }
422
423 // This case fails on all AMD platforms (Mac, Linux, Win).
424 // TODO(zmo): This actually passes on certain AMD cards, but we don't have
425 // a way to do device specific handling yet.
426 if (IsAMD())
427 {
428 std::cout << "Test skipped on AMD." << std::endl;
429 return;
430 }
431
432 const std::string &vertexShaderSource =
433 "#version 300 es\n"
434 "in vec2 position;\n"
435 "out float v;\n"
436 "struct S {\n"
437 " highp ivec3 a;\n"
438 " mediump ivec2 b[4];\n"
439 "};\n"
440 "layout(std140) uniform blockName0 {\n"
441 " S s0;\n"
442 " lowp vec2 v0;\n"
443 " S s1[2];\n"
444 " highp uint u0;\n"
445 "};\n"
446 "layout(std140) uniform blockName1 {\n"
447 " float f1;\n"
448 " bool b1;\n"
449 "} instanceName1;\n"
450 "layout(shared) uniform blockName2 {\n"
451 " float f2;\n"
452 "};\n"
453 "layout(packed) uniform blockName3 {\n"
454 " float f3;\n"
455 "};\n"
456 "void main() {\n"
457 " v = instanceName1.f1;\n"
458 " gl_Position = vec4(position, 0, 1);\n"
459 "}";
460
461 const std::string &fragmentShaderSource =
462 "#version 300 es\n"
463 "precision highp float;\n"
464 "in float v;\n"
465 "out vec4 color;\n"
466 "void main() {\n"
467 " color = vec4(v, 0, 0, 1);\n"
468 "}";
469
470 ANGLE_GL_PROGRAM(program, vertexShaderSource, fragmentShaderSource);
471
472 // Note that the packed |blockName3| might (or might not) be optimized out.
473 GLint activeUniforms;
474 glGetProgramiv(program.get(), GL_ACTIVE_UNIFORMS, &activeUniforms);
475 EXPECT_GE(activeUniforms, 11);
476
477 GLint activeUniformBlocks;
478 glGetProgramiv(program.get(), GL_ACTIVE_UNIFORM_BLOCKS, &activeUniformBlocks);
479 EXPECT_GE(activeUniformBlocks, 3);
480
481 GLint maxLength, size;
482 GLenum type;
483 GLsizei length;
484 glGetProgramiv(program.get(), GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
485 std::vector<GLchar> strBuffer(maxLength + 1, 0);
486
487 glGetActiveUniform(program.get(), 0, maxLength, &length, &size, &type, &strBuffer[0]);
488 ASSERT_GL_NO_ERROR();
489 EXPECT_EQ(1, size);
490 EXPECT_EQ("s0.a", std::string(&strBuffer[0]));
491
492 glGetActiveUniform(program.get(), 1, maxLength, &length, &size, &type, &strBuffer[0]);
493 ASSERT_GL_NO_ERROR();
494 EXPECT_EQ(4, size);
495 EXPECT_EQ("s0.b[0]", std::string(&strBuffer[0]));
496
497 glGetActiveUniform(program.get(), 2, maxLength, &length, &size, &type, &strBuffer[0]);
498 ASSERT_GL_NO_ERROR();
499 EXPECT_EQ(1, size);
500 EXPECT_EQ("v0", std::string(&strBuffer[0]));
501
502 glGetActiveUniform(program.get(), 3, maxLength, &length, &size, &type, &strBuffer[0]);
503 ASSERT_GL_NO_ERROR();
504 EXPECT_EQ(1, size);
505 EXPECT_EQ("s1[0].a", std::string(&strBuffer[0]));
506
507 glGetActiveUniform(program.get(), 4, maxLength, &length, &size, &type, &strBuffer[0]);
508 ASSERT_GL_NO_ERROR();
509 EXPECT_EQ(4, size);
510 EXPECT_EQ("s1[0].b[0]", std::string(&strBuffer[0]));
511
512 glGetActiveUniform(program.get(), 5, maxLength, &length, &size, &type, &strBuffer[0]);
513 ASSERT_GL_NO_ERROR();
514 EXPECT_EQ(1, size);
515 EXPECT_EQ("s1[1].a", std::string(&strBuffer[0]));
516
517 glGetActiveUniform(program.get(), 6, maxLength, &length, &size, &type, &strBuffer[0]);
518 ASSERT_GL_NO_ERROR();
519 EXPECT_EQ(4, size);
520 EXPECT_EQ("s1[1].b[0]", std::string(&strBuffer[0]));
521
522 glGetActiveUniform(program.get(), 7, maxLength, &length, &size, &type, &strBuffer[0]);
523 ASSERT_GL_NO_ERROR();
524 EXPECT_EQ(1, size);
525 EXPECT_EQ("u0", std::string(&strBuffer[0]));
526
527 glGetActiveUniform(program.get(), 8, maxLength, &length, &size, &type, &strBuffer[0]);
528 ASSERT_GL_NO_ERROR();
529 EXPECT_EQ(1, size);
530 EXPECT_EQ("blockName1.f1", std::string(&strBuffer[0]));
531
532 glGetActiveUniform(program.get(), 9, maxLength, &length, &size, &type, &strBuffer[0]);
533 ASSERT_GL_NO_ERROR();
534 EXPECT_EQ(1, size);
535 EXPECT_EQ("blockName1.b1", std::string(&strBuffer[0]));
536
537 glGetActiveUniform(program.get(), 10, maxLength, &length, &size, &type, &strBuffer[0]);
538 ASSERT_GL_NO_ERROR();
539 EXPECT_EQ(1, size);
540 EXPECT_EQ("f2", std::string(&strBuffer[0]));
541 }
542
543 // Test that using a very large buffer to back a small uniform block works OK.
TEST_P(UniformBufferTest,VeryLarge)544 TEST_P(UniformBufferTest, VeryLarge)
545 {
546 glClear(GL_COLOR_BUFFER_BIT);
547 float floatData[4] = {0.5f, 0.75f, 0.25f, 1.0f};
548
549 GLsizei bigSize = 4096 * 64;
550 std::vector<GLubyte> zero(bigSize, 0);
551
552 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
553 glBufferData(GL_UNIFORM_BUFFER, bigSize, zero.data(), GL_STATIC_DRAW);
554 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(float) * 4, floatData);
555
556 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
557
558 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
559 drawQuad(mProgram, "position", 0.5f);
560
561 ASSERT_GL_NO_ERROR();
562 EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
563 }
564
565 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
566 ANGLE_INSTANTIATE_TEST(UniformBufferTest,
567 ES3_D3D11(),
568 ES3_D3D11_FL11_1(),
569 ES3_D3D11_FL11_1_REFERENCE(),
570 ES3_OPENGL(),
571 ES3_OPENGLES());
572
573 } // namespace
574