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 #include "util/random_utils.h"
10
11 using namespace angle;
12
13 namespace
14 {
15
16 class UniformBufferTest : public ANGLETest<>
17 {
18 protected:
UniformBufferTest()19 UniformBufferTest()
20 {
21 setWindowWidth(128);
22 setWindowHeight(128);
23 setConfigRedBits(8);
24 setConfigGreenBits(8);
25 setConfigBlueBits(8);
26 setConfigAlphaBits(8);
27 }
28
testSetUp()29 void testSetUp() override
30 {
31 mkFS = R"(#version 300 es
32 precision highp float;
33 uniform uni { vec4 color; };
34 out vec4 fragColor;
35 void main()
36 {
37 fragColor = color;
38 })";
39
40 mProgram = CompileProgram(essl3_shaders::vs::Simple(), mkFS);
41 ASSERT_NE(mProgram, 0u);
42
43 mUniformBufferIndex = glGetUniformBlockIndex(mProgram, "uni");
44 ASSERT_NE(mUniformBufferIndex, -1);
45
46 glGenBuffers(1, &mUniformBuffer);
47
48 ASSERT_GL_NO_ERROR();
49 }
50
testTearDown()51 void testTearDown() override
52 {
53 glDeleteBuffers(1, &mUniformBuffer);
54 glDeleteProgram(mProgram);
55 }
56
57 const char *mkFS;
58 GLuint mProgram;
59 GLint mUniformBufferIndex;
60 GLuint mUniformBuffer;
61 };
62
63 // Basic UBO functionality.
TEST_P(UniformBufferTest,Simple)64 TEST_P(UniformBufferTest, Simple)
65 {
66 glClear(GL_COLOR_BUFFER_BIT);
67 float floatData[4] = {0.5f, 0.75f, 0.25f, 1.0f};
68
69 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
70 glBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 4, floatData, GL_STATIC_DRAW);
71
72 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
73
74 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
75 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
76
77 ASSERT_GL_NO_ERROR();
78 EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
79 }
80
81 // Test a scenario that draws then update UBO (using bufferData or bufferSubData or mapBuffer) then
82 // draws with updated data.
TEST_P(UniformBufferTest,DrawThenUpdateThenDraw)83 TEST_P(UniformBufferTest, DrawThenUpdateThenDraw)
84 {
85 constexpr char kVS[] = R"(#version 300 es
86 precision highp float;
87
88 void main()
89 {
90 vec2 position = vec2(float(gl_VertexID >> 1), float(gl_VertexID & 1));
91 position = 2.0 * position - 1.0;
92 gl_Position = vec4(position.x, position.y, 0.0, 1.0);
93 })";
94
95 enum class BufferUpdateMethod
96 {
97 BUFFER_DATA,
98 BUFFER_SUB_DATA,
99 MAP_BUFFER,
100 };
101
102 ANGLE_GL_PROGRAM(program, kVS, mkFS);
103 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "uni");
104 ASSERT_NE(uniformBufferIndex, -1);
105
106 for (BufferUpdateMethod method :
107 {BufferUpdateMethod::BUFFER_DATA, BufferUpdateMethod::BUFFER_SUB_DATA,
108 BufferUpdateMethod::MAP_BUFFER})
109 {
110 glClear(GL_COLOR_BUFFER_BIT);
111 float floatData1[4] = {0.25f, 0.75f, 0.125f, 1.0f};
112
113 GLBuffer uniformBuffer;
114 glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer);
115 glBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 4, floatData1, GL_DYNAMIC_DRAW);
116
117 glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniformBuffer);
118
119 glEnable(GL_BLEND);
120 glBlendFunc(GL_ONE, GL_ONE);
121
122 glUniformBlockBinding(program, uniformBufferIndex, 0);
123 glUseProgram(program);
124 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
125
126 float floatData2[4] = {0.25f, 0.0f, 0.125f, 0.0f};
127 switch (method)
128 {
129 case BufferUpdateMethod::BUFFER_DATA:
130 glBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 4, floatData2, GL_DYNAMIC_DRAW);
131 break;
132 case BufferUpdateMethod::BUFFER_SUB_DATA:
133 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(float) * 4, floatData2);
134 break;
135 case BufferUpdateMethod::MAP_BUFFER:
136 void *mappedBuffer =
137 glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(float) * 4, GL_MAP_WRITE_BIT);
138 memcpy(mappedBuffer, floatData2, sizeof(floatData2));
139 glUnmapBuffer(GL_UNIFORM_BUFFER);
140 break;
141 }
142 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
143
144 ASSERT_GL_NO_ERROR();
145 EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
146 }
147 }
148
149 // Test that using a UBO with a non-zero offset and size actually works.
150 // The first step of this test renders a color from a UBO with a zero offset.
151 // The second step renders a color from a UBO with a non-zero offset.
TEST_P(UniformBufferTest,UniformBufferRange)152 TEST_P(UniformBufferTest, UniformBufferRange)
153 {
154 int px = getWindowWidth() / 2;
155 int py = getWindowHeight() / 2;
156
157 // Query the uniform buffer alignment requirement
158 GLint alignment;
159 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
160
161 GLint64 maxUniformBlockSize;
162 glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
163 if (alignment >= maxUniformBlockSize)
164 {
165 // ANGLE doesn't implement UBO offsets for this platform.
166 // Ignore the test case.
167 return;
168 }
169
170 ASSERT_GL_NO_ERROR();
171
172 // Let's create a buffer which contains two vec4.
173 GLuint vec4Size = 4 * sizeof(float);
174 GLuint stride = 0;
175 do
176 {
177 stride += alignment;
178 } while (stride < vec4Size);
179
180 std::vector<char> v(2 * stride);
181 float *first = reinterpret_cast<float *>(v.data());
182 float *second = reinterpret_cast<float *>(v.data() + stride);
183
184 first[0] = 10.f / 255.f;
185 first[1] = 20.f / 255.f;
186 first[2] = 30.f / 255.f;
187 first[3] = 40.f / 255.f;
188
189 second[0] = 110.f / 255.f;
190 second[1] = 120.f / 255.f;
191 second[2] = 130.f / 255.f;
192 second[3] = 140.f / 255.f;
193
194 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
195 // We use on purpose a size which is not a multiple of the alignment.
196 glBufferData(GL_UNIFORM_BUFFER, stride + vec4Size, v.data(), GL_STATIC_DRAW);
197
198 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
199
200 EXPECT_GL_NO_ERROR();
201
202 // Bind the first part of the uniform buffer and draw
203 // Use a size which is smaller than the alignment to check
204 // to check that this case is handle correctly in the conversion to 11.1.
205 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, 0, vec4Size);
206 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
207 EXPECT_GL_NO_ERROR();
208 EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
209
210 // Bind the second part of the uniform buffer and draw
211 // Furthermore the D3D11.1 backend will internally round the vec4Size (16 bytes) to a stride
212 // (256 bytes) hence it will try to map the range [stride, 2 * stride] which is out-of-bound of
213 // the buffer bufferSize = stride + vec4Size < 2 * stride. Ensure that this behaviour works.
214 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, stride, vec4Size);
215 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
216 EXPECT_GL_NO_ERROR();
217 EXPECT_PIXEL_EQ(px, py, 110, 120, 130, 140);
218 }
219
220 // Test uniform block bindings.
TEST_P(UniformBufferTest,UniformBufferBindings)221 TEST_P(UniformBufferTest, UniformBufferBindings)
222 {
223 int px = getWindowWidth() / 2;
224 int py = getWindowHeight() / 2;
225
226 ASSERT_GL_NO_ERROR();
227
228 // Let's create a buffer which contains one vec4.
229 GLuint vec4Size = 4 * sizeof(float);
230 std::vector<char> v(vec4Size);
231 float *first = reinterpret_cast<float *>(v.data());
232
233 first[0] = 10.f / 255.f;
234 first[1] = 20.f / 255.f;
235 first[2] = 30.f / 255.f;
236 first[3] = 40.f / 255.f;
237
238 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
239 glBufferData(GL_UNIFORM_BUFFER, vec4Size, v.data(), GL_STATIC_DRAW);
240
241 EXPECT_GL_NO_ERROR();
242
243 // Try to bind the buffer to binding point 2
244 glUniformBlockBinding(mProgram, mUniformBufferIndex, 2);
245 glBindBufferBase(GL_UNIFORM_BUFFER, 2, mUniformBuffer);
246 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
247 EXPECT_GL_NO_ERROR();
248 EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
249
250 // Clear the framebuffer
251 glClearColor(0.0, 0.0, 0.0, 0.0);
252 glClear(GL_COLOR_BUFFER_BIT);
253 EXPECT_PIXEL_EQ(px, py, 0, 0, 0, 0);
254
255 // Try to bind the buffer to another binding point
256 glUniformBlockBinding(mProgram, mUniformBufferIndex, 5);
257 glBindBufferBase(GL_UNIFORM_BUFFER, 5, mUniformBuffer);
258 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
259 EXPECT_GL_NO_ERROR();
260 EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
261 }
262
263 // Test when the only change between draw calls is the change in the uniform binding range.
TEST_P(UniformBufferTest,BufferBindingRangeChange)264 TEST_P(UniformBufferTest, BufferBindingRangeChange)
265 {
266 constexpr GLsizei kVec4Size = 4 * sizeof(float);
267
268 GLint alignment;
269 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
270 if (alignment < kVec4Size)
271 {
272 alignment = kVec4Size;
273 }
274 ASSERT_EQ(alignment % 4, 0);
275
276 // Put two colors in the uniform buffer, the sum of which is yellow.
277 // Note: |alignment| is in bytes, so we can place each uniform in |alignment/4| floats.
278 std::vector<float> colors(alignment / 2);
279 // Half red
280 colors[0] = 0.55;
281 colors[1] = 0.0;
282 colors[2] = 0.0;
283 colors[3] = 0.35;
284 // Greenish yellow
285 colors[alignment / 4 + 0] = 0.55;
286 colors[alignment / 4 + 1] = 1.0;
287 colors[alignment / 4 + 2] = 0.0;
288 colors[alignment / 4 + 3] = 0.75;
289
290 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
291 glBufferData(GL_UNIFORM_BUFFER, alignment * 2, colors.data(), GL_STATIC_DRAW);
292
293 const GLint positionLoc = glGetAttribLocation(mProgram, essl3_shaders::PositionAttrib());
294 setupQuadVertexBuffer(0.5f, 1.0f);
295 glEnableVertexAttribArray(positionLoc);
296 glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
297
298 // Enable blending
299 glEnable(GL_BLEND);
300 glBlendFunc(GL_ONE, GL_ONE);
301
302 glClearColor(0, 0, 0, 0);
303 glClear(GL_COLOR_BUFFER_BIT);
304
305 // Draw twice, binding the uniform buffer to a different range each time
306 glUseProgram(mProgram);
307 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, 0, kVec4Size);
308 glDrawArrays(GL_TRIANGLES, 0, 6);
309 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, alignment, kVec4Size);
310 glDrawArrays(GL_TRIANGLES, 0, 6);
311 EXPECT_GL_NO_ERROR();
312
313 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::yellow);
314 }
315
316 // Test when glUniformBlockBinding is called between draws while the program is not current.
317 // Regression test for a missing dirty bit bug in this scenario.
TEST_P(UniformBufferTest,BufferBlockBindingChange)318 TEST_P(UniformBufferTest, BufferBlockBindingChange)
319 {
320 constexpr GLsizei kVec4Size = 4 * sizeof(float);
321
322 GLint alignment;
323 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
324 if (alignment < kVec4Size)
325 {
326 alignment = kVec4Size;
327 }
328 ASSERT_EQ(alignment % 4, 0);
329
330 // Put two colors in the uniform buffer, the sum of which is yellow.
331 // Note: |alignment| is in bytes, so we can place each uniform in |alignment/4| floats.
332 std::vector<float> colors(alignment / 2);
333 // Half red
334 colors[0] = 0.55;
335 colors[1] = 0.0;
336 colors[2] = 0.0;
337 colors[3] = 0.35;
338 // Greenish yellow
339 colors[alignment / 4 + 0] = 0.55;
340 colors[alignment / 4 + 1] = 1.0;
341 colors[alignment / 4 + 2] = 0.0;
342 colors[alignment / 4 + 3] = 0.75;
343
344 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
345 glBufferData(GL_UNIFORM_BUFFER, alignment * 2, colors.data(), GL_STATIC_DRAW);
346
347 const GLint positionLoc = glGetAttribLocation(mProgram, essl3_shaders::PositionAttrib());
348 setupQuadVertexBuffer(0.5f, 1.0f);
349 glEnableVertexAttribArray(positionLoc);
350 glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
351
352 // Enable blending
353 glEnable(GL_BLEND);
354 glBlendFunc(GL_ONE, GL_ONE);
355
356 glClearColor(0, 0, 0, 0);
357 glClear(GL_COLOR_BUFFER_BIT);
358
359 // Draw twice, binding the uniform buffer to a different range each time
360 glUseProgram(mProgram);
361 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, 0, kVec4Size);
362 glDrawArrays(GL_TRIANGLES, 0, 6);
363
364 // Change the block binding while the program is not current
365 glUseProgram(0);
366 glUniformBlockBinding(mProgram, 0, 1);
367 glUseProgram(mProgram);
368
369 glBindBufferRange(GL_UNIFORM_BUFFER, 1, mUniformBuffer, alignment, kVec4Size);
370 glDrawArrays(GL_TRIANGLES, 0, 6);
371 EXPECT_GL_NO_ERROR();
372
373 EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::yellow);
374 }
375
376 // Update a UBO many time and verify that ANGLE uses the latest version of the data.
377 // https://code.google.com/p/angleproject/issues/detail?id=965
TEST_P(UniformBufferTest,UniformBufferManyUpdates)378 TEST_P(UniformBufferTest, UniformBufferManyUpdates)
379 {
380 // TODO(jmadill): Figure out why this fails on OSX Intel OpenGL.
381 ANGLE_SKIP_TEST_IF(IsIntel() && IsMac() && IsOpenGL());
382
383 int px = getWindowWidth() / 2;
384 int py = getWindowHeight() / 2;
385
386 ASSERT_GL_NO_ERROR();
387
388 float data[4];
389
390 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
391 glBufferData(GL_UNIFORM_BUFFER, sizeof(data), nullptr, GL_DYNAMIC_DRAW);
392 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
393 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
394
395 EXPECT_GL_NO_ERROR();
396
397 // Repeteadly update the data and draw
398 for (size_t i = 0; i < 10; ++i)
399 {
400 data[0] = (i + 10.f) / 255.f;
401 data[1] = (i + 20.f) / 255.f;
402 data[2] = (i + 30.f) / 255.f;
403 data[3] = (i + 40.f) / 255.f;
404
405 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(data), data);
406
407 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
408 EXPECT_GL_NO_ERROR();
409 EXPECT_PIXEL_EQ(px, py, i + 10, i + 20, i + 30, i + 40);
410 }
411 }
412
413 // Use a large number of buffer ranges (compared to the actual size of the UBO)
TEST_P(UniformBufferTest,ManyUniformBufferRange)414 TEST_P(UniformBufferTest, ManyUniformBufferRange)
415 {
416 int px = getWindowWidth() / 2;
417 int py = getWindowHeight() / 2;
418
419 // Query the uniform buffer alignment requirement
420 GLint alignment;
421 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
422
423 GLint64 maxUniformBlockSize;
424 glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
425 if (alignment >= maxUniformBlockSize)
426 {
427 // ANGLE doesn't implement UBO offsets for this platform.
428 // Ignore the test case.
429 return;
430 }
431
432 ASSERT_GL_NO_ERROR();
433
434 // Let's create a buffer which contains eight vec4.
435 GLuint vec4Size = 4 * sizeof(float);
436 GLuint stride = 0;
437 do
438 {
439 stride += alignment;
440 } while (stride < vec4Size);
441
442 std::vector<char> v(8 * stride);
443
444 for (size_t i = 0; i < 8; ++i)
445 {
446 float *data = reinterpret_cast<float *>(v.data() + i * stride);
447
448 data[0] = (i + 10.f) / 255.f;
449 data[1] = (i + 20.f) / 255.f;
450 data[2] = (i + 30.f) / 255.f;
451 data[3] = (i + 40.f) / 255.f;
452 }
453
454 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
455 glBufferData(GL_UNIFORM_BUFFER, v.size(), v.data(), GL_STATIC_DRAW);
456
457 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
458
459 EXPECT_GL_NO_ERROR();
460
461 // Bind each possible offset
462 for (size_t i = 0; i < 8; ++i)
463 {
464 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, i * stride, stride);
465 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
466 EXPECT_GL_NO_ERROR();
467 EXPECT_PIXEL_EQ(px, py, 10 + i, 20 + i, 30 + i, 40 + i);
468 }
469
470 // Try to bind larger range
471 for (size_t i = 0; i < 7; ++i)
472 {
473 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, i * stride, 2 * stride);
474 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
475 EXPECT_GL_NO_ERROR();
476 EXPECT_PIXEL_EQ(px, py, 10 + i, 20 + i, 30 + i, 40 + i);
477 }
478
479 // Try to bind even larger range
480 for (size_t i = 0; i < 5; ++i)
481 {
482 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, i * stride, 4 * stride);
483 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
484 EXPECT_GL_NO_ERROR();
485 EXPECT_PIXEL_EQ(px, py, 10 + i, 20 + i, 30 + i, 40 + i);
486 }
487 }
488
489 // Tests that active uniforms have the right names.
TEST_P(UniformBufferTest,ActiveUniformNames)490 TEST_P(UniformBufferTest, ActiveUniformNames)
491 {
492 constexpr char kVS[] =
493 "#version 300 es\n"
494 "in vec2 position;\n"
495 "out vec2 v;\n"
496 "uniform blockName1 {\n"
497 " float f1;\n"
498 "} instanceName1;\n"
499 "uniform blockName2 {\n"
500 " float f2;\n"
501 "} instanceName2[1];\n"
502 "void main() {\n"
503 " v = vec2(instanceName1.f1, instanceName2[0].f2);\n"
504 " gl_Position = vec4(position, 0, 1);\n"
505 "}";
506
507 constexpr char kFS[] =
508 "#version 300 es\n"
509 "precision highp float;\n"
510 "in vec2 v;\n"
511 "out vec4 color;\n"
512 "void main() {\n"
513 " color = vec4(v, 0, 1);\n"
514 "}";
515
516 ANGLE_GL_PROGRAM(program, kVS, kFS);
517
518 GLint activeUniformBlocks;
519 glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &activeUniformBlocks);
520 ASSERT_EQ(2, activeUniformBlocks);
521
522 GLuint index = glGetUniformBlockIndex(program, "blockName1");
523 EXPECT_NE(GL_INVALID_INDEX, index);
524 ASSERT_GL_NO_ERROR();
525
526 index = glGetUniformBlockIndex(program, "blockName2[0]");
527 EXPECT_NE(GL_INVALID_INDEX, index);
528 ASSERT_GL_NO_ERROR();
529
530 GLint activeUniforms;
531 glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &activeUniforms);
532
533 ASSERT_EQ(2, activeUniforms);
534
535 GLint size;
536 GLenum type;
537 GLint maxLength;
538 GLsizei length;
539
540 glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
541 std::vector<GLchar> strUniformNameBuffer(maxLength + 1, 0);
542 const GLchar *uniformNames[1];
543 uniformNames[0] = "blockName1.f1";
544 glGetUniformIndices(program, 1, uniformNames, &index);
545 EXPECT_NE(GL_INVALID_INDEX, index);
546 ASSERT_GL_NO_ERROR();
547 glGetActiveUniform(program, index, maxLength, &length, &size, &type, &strUniformNameBuffer[0]);
548 EXPECT_EQ(1, size);
549 EXPECT_GLENUM_EQ(GL_FLOAT, type);
550 EXPECT_EQ("blockName1.f1", std::string(&strUniformNameBuffer[0]));
551
552 uniformNames[0] = "blockName2.f2";
553 glGetUniformIndices(program, 1, uniformNames, &index);
554 EXPECT_NE(GL_INVALID_INDEX, index);
555 ASSERT_GL_NO_ERROR();
556 glGetActiveUniform(program, index, maxLength, &length, &size, &type, &strUniformNameBuffer[0]);
557 EXPECT_EQ(1, size);
558 EXPECT_GLENUM_EQ(GL_FLOAT, type);
559 EXPECT_EQ("blockName2.f2", std::string(&strUniformNameBuffer[0]));
560 }
561
562 // Tests active uniforms and blocks when the layout is std140, shared and packed.
TEST_P(UniformBufferTest,ActiveUniformNumberAndName)563 TEST_P(UniformBufferTest, ActiveUniformNumberAndName)
564 {
565 constexpr char kVS[] =
566 "#version 300 es\n"
567 "in vec2 position;\n"
568 "out float v;\n"
569 "struct S {\n"
570 " highp ivec3 a;\n"
571 " mediump ivec2 b[4];\n"
572 "};\n"
573 "layout(std140) uniform blockName0 {\n"
574 " S s0;\n"
575 " lowp vec2 v0;\n"
576 " S s1[2];\n"
577 " highp uint u0;\n"
578 "};\n"
579 "layout(std140) uniform blockName1 {\n"
580 " float f1;\n"
581 " bool b1;\n"
582 "} instanceName1;\n"
583 "layout(shared) uniform blockName2 {\n"
584 " float f2;\n"
585 "};\n"
586 "layout(packed) uniform blockName3 {\n"
587 " float f3;\n"
588 "};\n"
589 "void main() {\n"
590 " v = instanceName1.f1;\n"
591 " gl_Position = vec4(position, 0, 1);\n"
592 "}";
593
594 constexpr char kFS[] =
595 "#version 300 es\n"
596 "precision highp float;\n"
597 "in float v;\n"
598 "out vec4 color;\n"
599 "void main() {\n"
600 " color = vec4(v, 0, 0, 1);\n"
601 "}";
602
603 ANGLE_GL_PROGRAM(program, kVS, kFS);
604
605 // Note that the packed |blockName3| might (or might not) be optimized out.
606 GLint activeUniforms;
607 glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &activeUniforms);
608 EXPECT_GE(activeUniforms, 11);
609
610 GLint activeUniformBlocks;
611 glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &activeUniformBlocks);
612 EXPECT_GE(activeUniformBlocks, 3);
613
614 GLint maxLength, size;
615 GLenum type;
616 GLsizei length;
617 GLuint index;
618 const GLchar *uniformNames[1];
619 glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
620 std::vector<GLchar> strBuffer(maxLength + 1, 0);
621
622 uniformNames[0] = "s0.a";
623 glGetUniformIndices(program, 1, uniformNames, &index);
624 EXPECT_NE(GL_INVALID_INDEX, index);
625 ASSERT_GL_NO_ERROR();
626 glGetActiveUniform(program, index, maxLength, &length, &size, &type, &strBuffer[0]);
627 EXPECT_EQ(1, size);
628 EXPECT_EQ("s0.a", std::string(&strBuffer[0]));
629
630 uniformNames[0] = "s0.b[0]";
631 glGetUniformIndices(program, 1, uniformNames, &index);
632 EXPECT_NE(GL_INVALID_INDEX, index);
633 ASSERT_GL_NO_ERROR();
634 glGetActiveUniform(program, index, maxLength, &length, &size, &type, &strBuffer[0]);
635 ASSERT_GL_NO_ERROR();
636 EXPECT_EQ(4, size);
637 EXPECT_EQ("s0.b[0]", std::string(&strBuffer[0]));
638
639 uniformNames[0] = "v0";
640 glGetUniformIndices(program, 1, uniformNames, &index);
641 EXPECT_NE(GL_INVALID_INDEX, index);
642 ASSERT_GL_NO_ERROR();
643 glGetActiveUniform(program, index, maxLength, &length, &size, &type, &strBuffer[0]);
644 ASSERT_GL_NO_ERROR();
645 EXPECT_EQ(1, size);
646 EXPECT_EQ("v0", std::string(&strBuffer[0]));
647
648 uniformNames[0] = "s1[0].a";
649 glGetUniformIndices(program, 1, uniformNames, &index);
650 EXPECT_NE(GL_INVALID_INDEX, index);
651 ASSERT_GL_NO_ERROR();
652 glGetActiveUniform(program, index, maxLength, &length, &size, &type, &strBuffer[0]);
653 ASSERT_GL_NO_ERROR();
654 EXPECT_EQ(1, size);
655 EXPECT_EQ("s1[0].a", std::string(&strBuffer[0]));
656
657 uniformNames[0] = "s1[0].b[0]";
658 glGetUniformIndices(program, 1, uniformNames, &index);
659 EXPECT_NE(GL_INVALID_INDEX, index);
660 ASSERT_GL_NO_ERROR();
661 glGetActiveUniform(program, index, maxLength, &length, &size, &type, &strBuffer[0]);
662 ASSERT_GL_NO_ERROR();
663 EXPECT_EQ(4, size);
664 EXPECT_EQ("s1[0].b[0]", std::string(&strBuffer[0]));
665
666 uniformNames[0] = "s1[1].a";
667 glGetUniformIndices(program, 1, uniformNames, &index);
668 EXPECT_NE(GL_INVALID_INDEX, index);
669 ASSERT_GL_NO_ERROR();
670 glGetActiveUniform(program, index, maxLength, &length, &size, &type, &strBuffer[0]);
671 ASSERT_GL_NO_ERROR();
672 EXPECT_EQ(1, size);
673 EXPECT_EQ("s1[1].a", std::string(&strBuffer[0]));
674
675 uniformNames[0] = "s1[1].b[0]";
676 glGetUniformIndices(program, 1, uniformNames, &index);
677 EXPECT_NE(GL_INVALID_INDEX, index);
678 ASSERT_GL_NO_ERROR();
679 glGetActiveUniform(program, index, maxLength, &length, &size, &type, &strBuffer[0]);
680 ASSERT_GL_NO_ERROR();
681 EXPECT_EQ(4, size);
682 EXPECT_EQ("s1[1].b[0]", std::string(&strBuffer[0]));
683
684 uniformNames[0] = "u0";
685 glGetUniformIndices(program, 1, uniformNames, &index);
686 EXPECT_NE(GL_INVALID_INDEX, index);
687 ASSERT_GL_NO_ERROR();
688 glGetActiveUniform(program, index, maxLength, &length, &size, &type, &strBuffer[0]);
689 ASSERT_GL_NO_ERROR();
690 EXPECT_EQ(1, size);
691 EXPECT_EQ("u0", std::string(&strBuffer[0]));
692
693 uniformNames[0] = "blockName1.f1";
694 glGetUniformIndices(program, 1, uniformNames, &index);
695 EXPECT_NE(GL_INVALID_INDEX, index);
696 ASSERT_GL_NO_ERROR();
697 glGetActiveUniform(program, index, maxLength, &length, &size, &type, &strBuffer[0]);
698 ASSERT_GL_NO_ERROR();
699 EXPECT_EQ(1, size);
700 EXPECT_EQ("blockName1.f1", std::string(&strBuffer[0]));
701
702 uniformNames[0] = "blockName1.b1";
703 glGetUniformIndices(program, 1, uniformNames, &index);
704 EXPECT_NE(GL_INVALID_INDEX, index);
705 ASSERT_GL_NO_ERROR();
706 glGetActiveUniform(program, index, maxLength, &length, &size, &type, &strBuffer[0]);
707 ASSERT_GL_NO_ERROR();
708 EXPECT_EQ(1, size);
709 EXPECT_EQ("blockName1.b1", std::string(&strBuffer[0]));
710
711 uniformNames[0] = "f2";
712 glGetUniformIndices(program, 1, uniformNames, &index);
713 EXPECT_NE(GL_INVALID_INDEX, index);
714 ASSERT_GL_NO_ERROR();
715 glGetActiveUniform(program, index, maxLength, &length, &size, &type, &strBuffer[0]);
716 ASSERT_GL_NO_ERROR();
717 EXPECT_EQ(1, size);
718 EXPECT_EQ("f2", std::string(&strBuffer[0]));
719 }
720
721 // Test that using a very large buffer to back a small uniform block works OK.
TEST_P(UniformBufferTest,VeryLarge)722 TEST_P(UniformBufferTest, VeryLarge)
723 {
724 glClear(GL_COLOR_BUFFER_BIT);
725 float floatData[4] = {0.5f, 0.75f, 0.25f, 1.0f};
726
727 GLsizei bigSize = 4096 * 64;
728 std::vector<GLubyte> zero(bigSize, 0);
729
730 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
731 glBufferData(GL_UNIFORM_BUFFER, bigSize, zero.data(), GL_STATIC_DRAW);
732 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(float) * 4, floatData);
733
734 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
735
736 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
737 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
738
739 ASSERT_GL_NO_ERROR();
740 EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
741 }
742
743 // Test that readback from a very large uniform buffer works OK.
TEST_P(UniformBufferTest,VeryLargeReadback)744 TEST_P(UniformBufferTest, VeryLargeReadback)
745 {
746 glClear(GL_COLOR_BUFFER_BIT);
747
748 // Generate some random data.
749 GLsizei bigSize = 4096 * 64;
750 std::vector<GLubyte> expectedData(bigSize);
751 for (GLsizei index = 0; index < bigSize; ++index)
752 {
753 expectedData[index] = static_cast<GLubyte>(index);
754 }
755
756 // Initialize the GL buffer.
757 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
758 glBufferData(GL_UNIFORM_BUFFER, bigSize, expectedData.data(), GL_STATIC_DRAW);
759
760 // Do a small update.
761 GLsizei smallSize = sizeof(float) * 4;
762 std::array<float, 4> floatData = {{0.5f, 0.75f, 0.25f, 1.0f}};
763 memcpy(expectedData.data(), floatData.data(), smallSize);
764
765 glBufferSubData(GL_UNIFORM_BUFFER, 0, smallSize, expectedData.data());
766
767 // Draw with the buffer.
768 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
769 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
770 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
771
772 ASSERT_GL_NO_ERROR();
773 EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
774
775 // Read back the large buffer data.
776 const void *mapPtr = glMapBufferRange(GL_UNIFORM_BUFFER, 0, bigSize, GL_MAP_READ_BIT);
777 ASSERT_GL_NO_ERROR();
778 const GLubyte *bytePtr = reinterpret_cast<const GLubyte *>(mapPtr);
779 std::vector<GLubyte> actualData(bytePtr, bytePtr + bigSize);
780 EXPECT_EQ(expectedData, actualData);
781
782 glUnmapBuffer(GL_UNIFORM_BUFFER);
783 }
784
785 // Test drawing with different sized uniform blocks from the same UBO, drawing a smaller uniform
786 // block before larger one.
TEST_P(UniformBufferTest,MultipleSizesSmallBeforeBig)787 TEST_P(UniformBufferTest, MultipleSizesSmallBeforeBig)
788 {
789 constexpr size_t kSizeOfVec4 = 4 * sizeof(float);
790 constexpr char kUniformName[] = "uni";
791 constexpr char kFS1[] = R"(#version 300 es
792 precision highp float;
793 layout(std140) uniform uni {
794 bool b;
795 };
796
797 out vec4 fragColor;
798 void main() {
799 fragColor = b ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
800 })";
801
802 constexpr char kFS2[] = R"(#version 300 es
803 precision highp float;
804 layout(std140) uniform uni {
805 bool b[2];
806 vec4 v;
807 };
808
809 out vec4 fragColor;
810 void main() {
811 fragColor = v;
812 })";
813
814 GLint offsetAlignmentInBytes;
815 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &offsetAlignmentInBytes);
816 ASSERT_EQ(offsetAlignmentInBytes % kSizeOfVec4, 0U);
817 GLint offsetAlignmentInVec4 = offsetAlignmentInBytes / kSizeOfVec4;
818
819 // Insert padding required by implementation to have first unform block at a non-zero
820 // offset.
821 int initialPadding = rx::roundUp(3, offsetAlignmentInVec4);
822 std::vector<float> uboData;
823 for (int n = 0; n < initialPadding; ++n)
824 {
825 uboData.insert(uboData.end(), {0.0f, 0.0f, 0.0f, 0.0f});
826 }
827
828 // First uniform block - a single bool
829 uboData.insert(uboData.end(), {1.0f, 0.0f, 0.0f, 0.0f});
830
831 // Insert padding required by implementation to align second uniform block.
832 for (int n = 0; n < offsetAlignmentInVec4 - 1; ++n)
833 {
834 uboData.insert(uboData.end(), {0.0f, 0.0f, 0.0f, 0.0f});
835 }
836
837 // Second uniform block
838 uboData.insert(uboData.end(), {0.0f, 0.0f, 0.0f, 0.0f});
839 uboData.insert(uboData.end(), {1.0f, 0.0f, 0.0f, 0.0f});
840 uboData.insert(uboData.end(), {0.0f, 1.0f, 0.0f, 1.0f});
841
842 ANGLE_GL_PROGRAM(program1, essl3_shaders::vs::Simple(), kFS1);
843 ANGLE_GL_PROGRAM(program2, essl3_shaders::vs::Simple(), kFS2);
844
845 // UBO containing 2 different uniform blocks
846 GLBuffer ubo;
847 glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo);
848 glBufferData(GL_UNIFORM_BUFFER, uboData.size() * sizeof(float), uboData.data(), GL_STATIC_DRAW);
849 ASSERT_GL_NO_ERROR();
850
851 // Clear
852 glClear(GL_COLOR_BUFFER_BIT);
853
854 // Draw with first uniform block
855 GLuint index = glGetUniformBlockIndex(program1, kUniformName);
856 EXPECT_NE(GL_INVALID_INDEX, index);
857 ASSERT_GL_NO_ERROR();
858
859 glBindBufferRange(GL_UNIFORM_BUFFER, 0, ubo, initialPadding * kSizeOfVec4, kSizeOfVec4);
860 ASSERT_GL_NO_ERROR();
861
862 glUniformBlockBinding(program1, index, 0);
863 drawQuad(program1, essl3_shaders::PositionAttrib(), 0.5f);
864 ASSERT_GL_NO_ERROR();
865
866 EXPECT_PIXEL_NEAR(0, 0, 0, 255, 0, 255, 1);
867
868 // Draw with second uniform block
869 index = glGetUniformBlockIndex(program2, kUniformName);
870 EXPECT_NE(GL_INVALID_INDEX, index);
871 ASSERT_GL_NO_ERROR();
872
873 glBindBufferRange(GL_UNIFORM_BUFFER, 0, ubo,
874 (initialPadding + offsetAlignmentInVec4) * kSizeOfVec4, 3 * kSizeOfVec4);
875 ASSERT_GL_NO_ERROR();
876
877 glUniformBlockBinding(program2, index, 0);
878 drawQuad(program2, essl3_shaders::PositionAttrib(), 0.5f);
879 ASSERT_GL_NO_ERROR();
880
881 EXPECT_PIXEL_NEAR(0, 0, 0, 255, 0, 255, 1);
882 }
883
884 class UniformBufferTest31 : public ANGLETest<>
885 {
886 protected:
UniformBufferTest31()887 UniformBufferTest31()
888 {
889 setWindowWidth(128);
890 setWindowHeight(128);
891 setConfigRedBits(8);
892 setConfigGreenBits(8);
893 setConfigBlueBits(8);
894 setConfigAlphaBits(8);
895 }
896 };
897
898 // Test uniform block bindings greater than GL_MAX_UNIFORM_BUFFER_BINDINGS cause compile error.
TEST_P(UniformBufferTest31,MaxUniformBufferBindingsExceeded)899 TEST_P(UniformBufferTest31, MaxUniformBufferBindingsExceeded)
900 {
901 GLint maxUniformBufferBindings;
902 glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferBindings);
903 std::string source =
904 "#version 310 es\n"
905 "in vec4 position;\n"
906 "layout(binding = ";
907 std::stringstream ss;
908 ss << maxUniformBufferBindings;
909 source = source + ss.str() +
910 ") uniform uni {\n"
911 " vec4 color;\n"
912 "};\n"
913 "void main()\n"
914 "{\n"
915 " gl_Position = position;\n"
916 "}";
917 GLuint shader = CompileShader(GL_VERTEX_SHADER, source.c_str());
918 EXPECT_EQ(0u, shader);
919 }
920
921 // Test uniform block bindings specified by layout in shader work properly.
TEST_P(UniformBufferTest31,UniformBufferBindings)922 TEST_P(UniformBufferTest31, UniformBufferBindings)
923 {
924 constexpr char kVS[] =
925 "#version 310 es\n"
926 "in vec4 position;\n"
927 "void main()\n"
928 "{\n"
929 " gl_Position = position;\n"
930 "}";
931 constexpr char kFS[] =
932 "#version 310 es\n"
933 "precision highp float;\n"
934 "layout(binding = 2) uniform uni {\n"
935 " vec4 color;\n"
936 "};\n"
937 "out vec4 fragColor;\n"
938 "void main()\n"
939 "{"
940 " fragColor = color;\n"
941 "}";
942
943 ANGLE_GL_PROGRAM(program, kVS, kFS);
944 GLuint uniformBufferIndex = glGetUniformBlockIndex(program, "uni");
945 ASSERT_NE(GL_INVALID_INDEX, uniformBufferIndex);
946 GLBuffer uniformBuffer;
947
948 int px = getWindowWidth() / 2;
949 int py = getWindowHeight() / 2;
950
951 ASSERT_GL_NO_ERROR();
952
953 // Let's create a buffer which contains one vec4.
954 GLuint vec4Size = 4 * sizeof(float);
955 std::vector<char> v(vec4Size);
956 float *first = reinterpret_cast<float *>(v.data());
957
958 first[0] = 10.f / 255.f;
959 first[1] = 20.f / 255.f;
960 first[2] = 30.f / 255.f;
961 first[3] = 40.f / 255.f;
962
963 glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer);
964 glBufferData(GL_UNIFORM_BUFFER, vec4Size, v.data(), GL_STATIC_DRAW);
965
966 EXPECT_GL_NO_ERROR();
967
968 glBindBufferBase(GL_UNIFORM_BUFFER, 2, uniformBuffer);
969 drawQuad(program, "position", 0.5f);
970 EXPECT_GL_NO_ERROR();
971 EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
972
973 // Clear the framebuffer
974 glClearColor(0.0, 0.0, 0.0, 0.0);
975 glClear(GL_COLOR_BUFFER_BIT);
976 EXPECT_PIXEL_EQ(px, py, 0, 0, 0, 0);
977
978 // Try to bind the buffer to another binding point
979 glUniformBlockBinding(program, uniformBufferIndex, 5);
980 glBindBufferBase(GL_UNIFORM_BUFFER, 5, uniformBuffer);
981 drawQuad(program, "position", 0.5f);
982 EXPECT_GL_NO_ERROR();
983 EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
984 }
985
986 // Test uniform blocks used as instanced array take next binding point for each subsequent element.
TEST_P(UniformBufferTest31,ConsecutiveBindingsForBlockArray)987 TEST_P(UniformBufferTest31, ConsecutiveBindingsForBlockArray)
988 {
989 constexpr char kFS[] =
990 "#version 310 es\n"
991 "precision highp float;\n"
992 "layout(binding = 2) uniform uni {\n"
993 " vec4 color;\n"
994 "} blocks[2];\n"
995 "out vec4 fragColor;\n"
996 "void main()\n"
997 "{\n"
998 " fragColor = blocks[0].color + blocks[1].color;\n"
999 "}";
1000
1001 ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
1002 std::array<GLBuffer, 2> uniformBuffers;
1003
1004 int px = getWindowWidth() / 2;
1005 int py = getWindowHeight() / 2;
1006
1007 ASSERT_GL_NO_ERROR();
1008
1009 // Let's create a buffer which contains one vec4.
1010 GLuint vec4Size = 4 * sizeof(float);
1011 std::vector<char> v(vec4Size);
1012 float *first = reinterpret_cast<float *>(v.data());
1013
1014 first[0] = 10.f / 255.f;
1015 first[1] = 20.f / 255.f;
1016 first[2] = 30.f / 255.f;
1017 first[3] = 40.f / 255.f;
1018
1019 glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffers[0]);
1020 glBufferData(GL_UNIFORM_BUFFER, vec4Size, v.data(), GL_STATIC_DRAW);
1021 EXPECT_GL_NO_ERROR();
1022 glBindBufferBase(GL_UNIFORM_BUFFER, 2, uniformBuffers[0]);
1023 ASSERT_GL_NO_ERROR();
1024 glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffers[1]);
1025 glBufferData(GL_UNIFORM_BUFFER, vec4Size, v.data(), GL_STATIC_DRAW);
1026 EXPECT_GL_NO_ERROR();
1027 glBindBufferBase(GL_UNIFORM_BUFFER, 3, uniformBuffers[1]);
1028
1029 drawQuad(program, essl31_shaders::PositionAttrib(), 0.5f);
1030 EXPECT_GL_NO_ERROR();
1031 EXPECT_PIXEL_EQ(px, py, 20, 40, 60, 80);
1032 }
1033
1034 // Test the layout qualifier binding must be both specified(ESSL 3.10.4 section 9.2).
TEST_P(UniformBufferTest31,BindingMustBeBothSpecified)1035 TEST_P(UniformBufferTest31, BindingMustBeBothSpecified)
1036 {
1037 constexpr char kVS[] =
1038 "#version 310 es\n"
1039 "in vec4 position;\n"
1040 "uniform uni\n"
1041 "{\n"
1042 " vec4 color;\n"
1043 "} block;\n"
1044 "void main()\n"
1045 "{\n"
1046 " gl_Position = position + block.color;\n"
1047 "}";
1048 constexpr char kFS[] =
1049 "#version 310 es\n"
1050 "precision highp float;\n"
1051 "layout(binding = 0) uniform uni\n"
1052 "{\n"
1053 " vec4 color;\n"
1054 "} block;\n"
1055 "out vec4 fragColor;\n"
1056 "void main()\n"
1057 "{\n"
1058 " fragColor = block.color;\n"
1059 "}";
1060 GLuint program = CompileProgram(kVS, kFS);
1061 ASSERT_EQ(0u, program);
1062 }
1063
1064 // Test that uploading data to buffer that's in use then using it as indirect buffer works.
TEST_P(UniformBufferTest31,UseAsUBOThenUpdateThenDrawIndirect)1065 TEST_P(UniformBufferTest31, UseAsUBOThenUpdateThenDrawIndirect)
1066 {
1067 // http://anglebug.com/42264362
1068 ANGLE_SKIP_TEST_IF(IsD3D11());
1069
1070 // http://anglebug.com/42264411
1071 ANGLE_SKIP_TEST_IF(IsVulkan() && IsPixel2());
1072
1073 const std::array<uint32_t, 4> kInitialData = {100, 200, 300, 400};
1074 const std::array<uint32_t, 4> kUpdateData = {4, 1, 0, 0};
1075
1076 GLBuffer buffer;
1077 glBindBuffer(GL_UNIFORM_BUFFER, buffer);
1078 glBufferData(GL_UNIFORM_BUFFER, sizeof(kInitialData), kInitialData.data(), GL_DYNAMIC_DRAW);
1079 glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
1080 EXPECT_GL_NO_ERROR();
1081
1082 constexpr char kVerifyUBO[] = R"(#version 310 es
1083 precision mediump float;
1084 layout(binding = 0) uniform block {
1085 uvec4 data;
1086 } ubo;
1087 out vec4 colorOut;
1088 void main()
1089 {
1090 if (all(equal(ubo.data, uvec4(100, 200, 300, 400))))
1091 colorOut = vec4(0, 1.0, 0, 1.0);
1092 else
1093 colorOut = vec4(1.0, 0, 0, 1.0);
1094 })";
1095
1096 ANGLE_GL_PROGRAM(verifyUbo, essl31_shaders::vs::Simple(), kVerifyUBO);
1097 drawQuad(verifyUbo, essl31_shaders::PositionAttrib(), 0.5);
1098 EXPECT_GL_NO_ERROR();
1099
1100 // Update buffer data
1101 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(kInitialData), kUpdateData.data());
1102 EXPECT_GL_NO_ERROR();
1103
1104 // Draw indirect using the updated parameters
1105 constexpr char kVS[] = R"(#version 310 es
1106 void main()
1107 {
1108 // gl_VertexID x y
1109 // 0 -1 -1
1110 // 1 1 -1
1111 // 2 -1 1
1112 // 3 1 1
1113 int bit0 = gl_VertexID & 1;
1114 int bit1 = gl_VertexID >> 1;
1115 gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, 0, 1);
1116 })";
1117
1118 constexpr char kFS[] = R"(#version 310 es
1119 precision mediump float;
1120 out vec4 colorOut;
1121 void main()
1122 {
1123 colorOut = vec4(0, 0, 1.0, 1.0);
1124 })";
1125
1126 ANGLE_GL_PROGRAM(draw, kVS, kFS);
1127 glUseProgram(draw);
1128
1129 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer);
1130 EXPECT_GL_NO_ERROR();
1131
1132 GLVertexArray vao;
1133 glBindVertexArray(vao);
1134
1135 glEnable(GL_BLEND);
1136 glBlendFunc(GL_ONE, GL_ONE);
1137 glDrawArraysIndirect(GL_TRIANGLE_STRIP, nullptr);
1138 EXPECT_GL_NO_ERROR();
1139
1140 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
1141 }
1142
1143 // Test four bindings of the same uniform buffer.
TEST_P(UniformBufferTest31,FourBindingsSameBuffer)1144 TEST_P(UniformBufferTest31, FourBindingsSameBuffer)
1145 {
1146 // Create a program with accesses from four UBO binding points.
1147 constexpr char kFS[] = R"(#version 310 es
1148 precision mediump float;
1149 layout (binding = 0) uniform block0 {
1150 vec4 color;
1151 } b0;
1152 layout (binding = 1) uniform block1 {
1153 vec4 color;
1154 } b1;
1155 layout (binding = 2) uniform block2 {
1156 vec4 color;
1157 } b2;
1158 layout (binding = 3) uniform block3 {
1159 vec4 color;
1160 } b3;
1161
1162 out vec4 outColor;
1163
1164 void main() {
1165 outColor = b0.color + b1.color + b2.color + b3.color;
1166 })";
1167
1168 // Create a UBO.
1169 constexpr GLfloat uboData[4] = {0.0, 0.25, 0.0, 0.25};
1170 GLBuffer ubo;
1171 glBindBuffer(GL_UNIFORM_BUFFER, ubo);
1172 glBufferData(GL_UNIFORM_BUFFER, sizeof(uboData), uboData, GL_STATIC_READ);
1173
1174 // Bind the same UBO to all four binding points.
1175 glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo);
1176 glBindBufferBase(GL_UNIFORM_BUFFER, 1, ubo);
1177 glBindBufferBase(GL_UNIFORM_BUFFER, 2, ubo);
1178 glBindBufferBase(GL_UNIFORM_BUFFER, 3, ubo);
1179
1180 ANGLE_GL_PROGRAM(uboProgram, essl31_shaders::vs::Simple(), kFS);
1181 drawQuad(uboProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f);
1182 EXPECT_GL_NO_ERROR();
1183
1184 // Four {0, 0.25, 0, 0.25} pixels should sum to green.
1185 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1186 }
1187
1188 // Test with a block containing an array of structs.
TEST_P(UniformBufferTest,BlockContainingArrayOfStructs)1189 TEST_P(UniformBufferTest, BlockContainingArrayOfStructs)
1190 {
1191 constexpr char kFS[] =
1192 "#version 300 es\n"
1193 "precision highp float;\n"
1194 "out vec4 my_FragColor;\n"
1195 "struct light_t {\n"
1196 " vec4 intensity;\n"
1197 "};\n"
1198 "const int maxLights = 2;\n"
1199 "layout(std140) uniform lightData { light_t lights[maxLights]; };\n"
1200 "vec4 processLight(vec4 lighting, light_t light)\n"
1201 "{\n"
1202 " return lighting + light.intensity;\n"
1203 "}\n"
1204 "void main()\n"
1205 "{\n"
1206 " vec4 lighting = vec4(0, 0, 0, 1);\n"
1207 " for (int n = 0; n < maxLights; n++)\n"
1208 " {\n"
1209 " lighting = processLight(lighting, lights[n]);\n"
1210 " }\n"
1211 " my_FragColor = lighting;\n"
1212 "}\n";
1213
1214 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
1215 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "lightData");
1216
1217 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
1218 const GLsizei kStructCount = 2;
1219 const GLsizei kVectorElementCount = 4;
1220 const GLsizei kBytesPerElement = 4;
1221 const GLsizei kDataSize = kStructCount * kVectorElementCount * kBytesPerElement;
1222 std::vector<GLubyte> v(kDataSize, 0);
1223 float *vAsFloat = reinterpret_cast<float *>(v.data());
1224
1225 vAsFloat[1] = 0.5f;
1226 vAsFloat[kVectorElementCount + 1] = 0.5f;
1227
1228 glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
1229
1230 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
1231 glUniformBlockBinding(program, uniformBufferIndex, 0);
1232 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
1233 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1234 }
1235
1236 // Test with a block instance array containing an array of structs.
TEST_P(UniformBufferTest,BlockArrayContainingArrayOfStructs)1237 TEST_P(UniformBufferTest, BlockArrayContainingArrayOfStructs)
1238 {
1239 constexpr char kFS[] =
1240 R"(#version 300 es
1241
1242 precision highp float;
1243 out vec4 my_FragColor;
1244 struct light_t
1245 {
1246 vec4 intensity;
1247 };
1248
1249 layout(std140) uniform lightData { light_t lights[2]; } buffers[2];
1250
1251 vec4 processLight(vec4 lighting, light_t light)
1252 {
1253 return lighting + light.intensity;
1254 }
1255 void main()
1256 {
1257 vec4 lighting = vec4(0, 0, 0, 1);
1258 lighting = processLight(lighting, buffers[0].lights[0]);
1259 lighting = processLight(lighting, buffers[1].lights[1]);
1260 my_FragColor = lighting;
1261 })";
1262
1263 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
1264 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "lightData[0]");
1265 GLint uniformBuffer2Index = glGetUniformBlockIndex(program, "lightData[1]");
1266
1267 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
1268 const GLsizei kStructCount = 2;
1269 const GLsizei kVectorElementCount = 4;
1270 const GLsizei kBytesPerElement = 4;
1271 const GLsizei kDataSize = kStructCount * kVectorElementCount * kBytesPerElement;
1272 std::vector<GLubyte> v(kDataSize, 0);
1273 float *vAsFloat = reinterpret_cast<float *>(v.data());
1274
1275 // In the first struct/vector of the first block
1276 vAsFloat[1] = 0.5f;
1277
1278 glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
1279
1280 GLBuffer uniformBuffer2;
1281 glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer2);
1282
1283 vAsFloat[1] = 0.0f;
1284 // In the second struct/vector of the second block
1285 vAsFloat[kVectorElementCount + 1] = 0.5f;
1286 glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
1287
1288 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
1289 glBindBufferBase(GL_UNIFORM_BUFFER, 1, uniformBuffer2);
1290 glUniformBlockBinding(program, uniformBufferIndex, 0);
1291 glUniformBlockBinding(program, uniformBuffer2Index, 1);
1292 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
1293 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1294 }
1295
1296 // Test with a block containing an array of structs containing arrays.
TEST_P(UniformBufferTest,BlockContainingArrayOfStructsContainingArrays)1297 TEST_P(UniformBufferTest, BlockContainingArrayOfStructsContainingArrays)
1298 {
1299 constexpr char kFS[] =
1300 R"(#version 300 es
1301 precision highp float;
1302 out vec4 my_FragColor;
1303 struct light_t
1304 {
1305 vec4 intensity[3];
1306 };
1307 const int maxLights = 2;
1308 layout(std140) uniform lightData { light_t lights[maxLights]; };
1309 vec4 processLight(vec4 lighting, light_t light)
1310 {
1311 return lighting + light.intensity[1];
1312 }
1313 void main()
1314 {
1315 vec4 lighting = vec4(0, 0, 0, 1);
1316 lighting = processLight(lighting, lights[0]);
1317 lighting = processLight(lighting, lights[1]);
1318 my_FragColor = lighting;
1319 })";
1320
1321 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
1322 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "lightData");
1323
1324 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
1325 const GLsizei kStructCount = 2;
1326 const GLsizei kVectorsPerStruct = 3;
1327 const GLsizei kElementsPerVector = 4;
1328 const GLsizei kBytesPerElement = 4;
1329 const GLsizei kDataSize =
1330 kStructCount * kVectorsPerStruct * kElementsPerVector * kBytesPerElement;
1331 std::vector<GLubyte> v(kDataSize, 0);
1332 float *vAsFloat = reinterpret_cast<float *>(v.data());
1333
1334 vAsFloat[kElementsPerVector + 1] = 0.5f;
1335 vAsFloat[kVectorsPerStruct * kElementsPerVector + kElementsPerVector + 1] = 0.5f;
1336
1337 glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
1338 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
1339 glUniformBlockBinding(program, uniformBufferIndex, 0);
1340 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
1341 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1342 }
1343
1344 // Test with a block containing nested structs.
TEST_P(UniformBufferTest,BlockContainingNestedStructs)1345 TEST_P(UniformBufferTest, BlockContainingNestedStructs)
1346 {
1347 constexpr char kFS[] =
1348 "#version 300 es\n"
1349 "precision highp float;\n"
1350 "out vec4 my_FragColor;\n"
1351 "struct light_t {\n"
1352 " vec4 intensity;\n"
1353 "};\n"
1354 "struct lightWrapper_t {\n"
1355 " light_t light;\n"
1356 "};\n"
1357 "const int maxLights = 2;\n"
1358 "layout(std140) uniform lightData { lightWrapper_t lightWrapper; };\n"
1359 "vec4 processLight(vec4 lighting, lightWrapper_t aLightWrapper)\n"
1360 "{\n"
1361 " return lighting + aLightWrapper.light.intensity;\n"
1362 "}\n"
1363 "void main()\n"
1364 "{\n"
1365 " vec4 lighting = vec4(0, 0, 0, 1);\n"
1366 " for (int n = 0; n < maxLights; n++)\n"
1367 " {\n"
1368 " lighting = processLight(lighting, lightWrapper);\n"
1369 " }\n"
1370 " my_FragColor = lighting;\n"
1371 "}\n";
1372
1373 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
1374 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "lightData");
1375
1376 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
1377 const GLsizei kVectorsPerStruct = 3;
1378 const GLsizei kElementsPerVector = 4;
1379 const GLsizei kBytesPerElement = 4;
1380 const GLsizei kDataSize = kVectorsPerStruct * kElementsPerVector * kBytesPerElement;
1381 std::vector<GLubyte> v(kDataSize, 0);
1382 float *vAsFloat = reinterpret_cast<float *>(v.data());
1383
1384 vAsFloat[1] = 1.0f;
1385
1386 glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
1387 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
1388 glUniformBlockBinding(program, uniformBufferIndex, 0);
1389 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
1390 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1391 }
1392
1393 // Tests GetUniformBlockIndex return value on error.
TEST_P(UniformBufferTest,GetUniformBlockIndexDefaultReturn)1394 TEST_P(UniformBufferTest, GetUniformBlockIndexDefaultReturn)
1395 {
1396 ASSERT_FALSE(glIsProgram(99));
1397 EXPECT_EQ(GL_INVALID_INDEX, glGetUniformBlockIndex(99, "farts"));
1398 EXPECT_GL_ERROR(GL_INVALID_VALUE);
1399 }
1400
1401 // Block names can be reserved names in GLSL, as long as they're not reserved in GLSL ES.
TEST_P(UniformBufferTest,UniformBlockReservedOpenGLName)1402 TEST_P(UniformBufferTest, UniformBlockReservedOpenGLName)
1403 {
1404 constexpr char kFS[] =
1405 "#version 300 es\n"
1406 "precision highp float;\n"
1407 "out vec4 my_FragColor;\n"
1408 "layout(std140) uniform buffer { vec4 color; };\n"
1409 "void main()\n"
1410 "{\n"
1411 " my_FragColor = color;\n"
1412 "}\n";
1413
1414 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
1415 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
1416
1417 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
1418 const GLsizei kElementsPerVector = 4;
1419 const GLsizei kBytesPerElement = 4;
1420 const GLsizei kDataSize = kElementsPerVector * kBytesPerElement;
1421 std::vector<GLubyte> v(kDataSize, 0);
1422 float *vAsFloat = reinterpret_cast<float *>(v.data());
1423
1424 vAsFloat[1] = 1.0f;
1425 vAsFloat[3] = 1.0f;
1426
1427 glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
1428 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
1429 glUniformBlockBinding(program, uniformBufferIndex, 0);
1430 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
1431 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1432 }
1433
1434 // Block instance names can be reserved names in GLSL, as long as they're not reserved in GLSL ES.
TEST_P(UniformBufferTest,UniformBlockInstanceReservedOpenGLName)1435 TEST_P(UniformBufferTest, UniformBlockInstanceReservedOpenGLName)
1436 {
1437 constexpr char kFS[] =
1438 "#version 300 es\n"
1439 "precision highp float;\n"
1440 "out vec4 my_FragColor;\n"
1441 "layout(std140) uniform dmat2 { vec4 color; } buffer;\n"
1442 "void main()\n"
1443 "{\n"
1444 " my_FragColor = buffer.color;\n"
1445 "}\n";
1446
1447 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
1448 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "dmat2");
1449
1450 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
1451 const GLsizei kElementsPerVector = 4;
1452 const GLsizei kBytesPerElement = 4;
1453 const GLsizei kDataSize = kElementsPerVector * kBytesPerElement;
1454 std::vector<GLubyte> v(kDataSize, 0);
1455 float *vAsFloat = reinterpret_cast<float *>(v.data());
1456
1457 vAsFloat[1] = 1.0f;
1458 vAsFloat[3] = 1.0f;
1459
1460 glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
1461 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
1462 glUniformBlockBinding(program, uniformBufferIndex, 0);
1463 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
1464 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1465 }
1466
1467 // Test that uniform block instance with nested structs that contain vec3s inside is handled
1468 // correctly. This is meant to test that HLSL structure padding to implement std140 layout works
1469 // together with uniform blocks.
TEST_P(UniformBufferTest,Std140UniformBlockInstanceWithNestedStructsContainingVec3s)1470 TEST_P(UniformBufferTest, Std140UniformBlockInstanceWithNestedStructsContainingVec3s)
1471 {
1472 // Got incorrect test result on non-NVIDIA Android - the alpha channel was not set correctly
1473 // from the second vector, possibly the platform doesn't implement std140 packing right?
1474 // http://anglebug.com/42260937
1475 ANGLE_SKIP_TEST_IF(IsAndroid() && !IsNVIDIA());
1476
1477 constexpr char kFS[] =
1478 R"(#version 300 es
1479
1480 precision highp float;
1481 out vec4 my_FragColor;
1482
1483 struct Sinner {
1484 vec3 v;
1485 };
1486
1487 struct S {
1488 Sinner s1;
1489 Sinner s2;
1490 };
1491
1492 layout(std140) uniform structBuffer { S s; } buffer;
1493
1494 void accessStruct(S s)
1495 {
1496 my_FragColor = vec4(s.s1.v.xy, s.s2.v.xy);
1497 }
1498
1499 void main()
1500 {
1501 accessStruct(buffer.s);
1502 })";
1503
1504 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
1505 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "structBuffer");
1506
1507 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
1508 const GLsizei kVectorsPerBlock = 2;
1509 const GLsizei kElementsPerPaddedVector = 4;
1510 const GLsizei kBytesPerElement = 4;
1511 const GLsizei kDataSize = kVectorsPerBlock * kElementsPerPaddedVector * kBytesPerElement;
1512 std::vector<GLubyte> v(kDataSize, 0);
1513 float *vAsFloat = reinterpret_cast<float *>(v.data());
1514
1515 // Set second value in each vec3.
1516 vAsFloat[1u] = 1.0f;
1517 vAsFloat[4u + 1u] = 1.0f;
1518
1519 glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
1520 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
1521 glUniformBlockBinding(program, uniformBufferIndex, 0);
1522 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
1523 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1524 }
1525
1526 // Tests the detaching shaders from the program and using uniform blocks works.
1527 // This covers a bug in ANGLE's D3D back-end.
TEST_P(UniformBufferTest,DetachShaders)1528 TEST_P(UniformBufferTest, DetachShaders)
1529 {
1530 GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
1531 ASSERT_NE(0u, vertexShader);
1532 GLuint kFS = CompileShader(GL_FRAGMENT_SHADER, mkFS);
1533 ASSERT_NE(0u, kFS);
1534
1535 GLuint program = glCreateProgram();
1536 glAttachShader(program, vertexShader);
1537 glAttachShader(program, kFS);
1538
1539 ASSERT_TRUE(LinkAttachedProgram(program));
1540
1541 glDetachShader(program, vertexShader);
1542 glDetachShader(program, kFS);
1543 glDeleteShader(vertexShader);
1544 glDeleteShader(kFS);
1545
1546 glClear(GL_COLOR_BUFFER_BIT);
1547 float floatData[4] = {0.5f, 0.75f, 0.25f, 1.0f};
1548
1549 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
1550 glBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 4, floatData, GL_STATIC_DRAW);
1551
1552 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
1553
1554 GLint uniformBufferIndex = glGetUniformBlockIndex(mProgram, "uni");
1555 ASSERT_NE(uniformBufferIndex, -1);
1556
1557 glUniformBlockBinding(program, uniformBufferIndex, 0);
1558 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
1559
1560 ASSERT_GL_NO_ERROR();
1561 EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
1562
1563 glDeleteProgram(program);
1564 }
1565
1566 // Test a uniform block where the whole block is set as row-major.
TEST_P(UniformBufferTest,Std140UniformBlockWithRowMajorQualifier)1567 TEST_P(UniformBufferTest, Std140UniformBlockWithRowMajorQualifier)
1568 {
1569 // AMD OpenGL driver doesn't seem to apply the row-major qualifier right.
1570 // http://anglebug.com/40096480
1571 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL() && !IsMac());
1572
1573 constexpr char kFS[] =
1574 R"(#version 300 es
1575
1576 precision highp float;
1577 out vec4 my_FragColor;
1578
1579 layout(std140, row_major) uniform matrixBuffer
1580 {
1581 mat2 m;
1582 } buffer;
1583
1584 void main()
1585 {
1586 // Vector constructor accesses elements in column-major order.
1587 my_FragColor = vec4(buffer.m);
1588 })";
1589
1590 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
1591 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "matrixBuffer");
1592
1593 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
1594 const GLsizei kElementsPerMatrix = 8; // Each mat2 row gets padded into a vec4.
1595 const GLsizei kBytesPerElement = 4;
1596 const GLsizei kDataSize = kElementsPerMatrix * kBytesPerElement;
1597 std::vector<GLubyte> v(kDataSize, 0);
1598 float *vAsFloat = reinterpret_cast<float *>(v.data());
1599
1600 vAsFloat[0u] = 1.0f;
1601 vAsFloat[1u] = 128.0f / 255.0f;
1602 vAsFloat[4u] = 64.0f / 255.0f;
1603 vAsFloat[5u] = 32.0f / 255.0f;
1604
1605 glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
1606 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
1607 glUniformBlockBinding(program, uniformBufferIndex, 0);
1608 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
1609 ASSERT_GL_NO_ERROR();
1610 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255, 64, 128, 32), 5);
1611 }
1612
1613 // Test a uniform block where an individual matrix field is set as row-major whereas the whole block
1614 // is set as column-major.
TEST_P(UniformBufferTest,Std140UniformBlockWithPerMemberRowMajorQualifier)1615 TEST_P(UniformBufferTest, Std140UniformBlockWithPerMemberRowMajorQualifier)
1616 {
1617 // AMD OpenGL driver doesn't seem to apply the row-major qualifier right.
1618 // http://anglebug.com/40096480
1619 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL() && !IsMac());
1620
1621 constexpr char kFS[] =
1622 R"(#version 300 es
1623
1624 precision highp float;
1625 out vec4 my_FragColor;
1626
1627 layout(std140, column_major) uniform matrixBuffer
1628 {
1629 layout(row_major) mat2 m;
1630 } buffer;
1631
1632 void main()
1633 {
1634 // Vector constructor accesses elements in column-major order.
1635 my_FragColor = vec4(buffer.m);
1636 })";
1637
1638 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
1639 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "matrixBuffer");
1640
1641 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
1642 const GLsizei kElementsPerMatrix = 8; // Each mat2 row gets padded into a vec4.
1643 const GLsizei kBytesPerElement = 4;
1644 const GLsizei kDataSize = kElementsPerMatrix * kBytesPerElement;
1645 std::vector<GLubyte> v(kDataSize, 0);
1646 float *vAsFloat = reinterpret_cast<float *>(v.data());
1647
1648 vAsFloat[0u] = 1.0f;
1649 vAsFloat[1u] = 128.0f / 255.0f;
1650 vAsFloat[4u] = 64.0f / 255.0f;
1651 vAsFloat[5u] = 32.0f / 255.0f;
1652
1653 glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
1654 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
1655 glUniformBlockBinding(program, uniformBufferIndex, 0);
1656 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
1657 ASSERT_GL_NO_ERROR();
1658 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255, 64, 128, 32), 5);
1659 }
1660
1661 // Test a uniform block where an individual matrix field is set as column-major whereas the whole
1662 // block is set as row-major.
TEST_P(UniformBufferTest,Std140UniformBlockWithPerMemberColumnMajorQualifier)1663 TEST_P(UniformBufferTest, Std140UniformBlockWithPerMemberColumnMajorQualifier)
1664 {
1665 constexpr char kFS[] =
1666 R"(#version 300 es
1667
1668 precision highp float;
1669 out vec4 my_FragColor;
1670
1671 layout(std140, row_major) uniform matrixBuffer
1672 {
1673 // 2 columns, 3 rows.
1674 layout(column_major) mat2x3 m;
1675 } buffer;
1676
1677 void main()
1678 {
1679 // Vector constructor accesses elements in column-major order.
1680 my_FragColor = vec4(buffer.m);
1681 })";
1682
1683 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
1684 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "matrixBuffer");
1685
1686 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
1687 const GLsizei kElementsPerMatrix = 8; // Each mat2x3 column gets padded into a vec4.
1688 const GLsizei kBytesPerElement = 4;
1689 const GLsizei kDataSize = kElementsPerMatrix * kBytesPerElement;
1690 std::vector<GLubyte> v(kDataSize, 0);
1691 float *vAsFloat = reinterpret_cast<float *>(v.data());
1692
1693 vAsFloat[0u] = 1.0f;
1694 vAsFloat[1u] = 192.0f / 255.0f;
1695 vAsFloat[2u] = 128.0f / 255.0f;
1696 vAsFloat[4u] = 96.0f / 255.0f;
1697 vAsFloat[5u] = 64.0f / 255.0f;
1698 vAsFloat[6u] = 32.0f / 255.0f;
1699
1700 glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
1701 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
1702 glUniformBlockBinding(program, uniformBufferIndex, 0);
1703 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
1704 ASSERT_GL_NO_ERROR();
1705 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255, 192, 128, 96), 5);
1706 }
1707
1708 // Test a uniform block where a struct field is set as row-major.
TEST_P(UniformBufferTest,Std140UniformBlockWithRowMajorQualifierOnStruct)1709 TEST_P(UniformBufferTest, Std140UniformBlockWithRowMajorQualifierOnStruct)
1710 {
1711 // AMD OpenGL driver doesn't seem to apply the row-major qualifier right.
1712 // http://anglebug.com/40096480
1713 ANGLE_SKIP_TEST_IF(IsAMD() && IsOpenGL() && !IsMac());
1714
1715 constexpr char kFS[] =
1716 R"(#version 300 es
1717
1718 precision highp float;
1719 out vec4 my_FragColor;
1720
1721 struct S
1722 {
1723 mat2 m;
1724 };
1725
1726 layout(std140) uniform matrixBuffer
1727 {
1728 layout(row_major) S s;
1729 } buffer;
1730
1731 void main()
1732 {
1733 // Vector constructor accesses elements in column-major order.
1734 my_FragColor = vec4(buffer.s.m);
1735 })";
1736
1737 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
1738 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "matrixBuffer");
1739
1740 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
1741 const GLsizei kElementsPerMatrix = 8; // Each mat2 row gets padded into a vec4.
1742 const GLsizei kBytesPerElement = 4;
1743 const GLsizei kDataSize = kElementsPerMatrix * kBytesPerElement;
1744 std::vector<GLubyte> v(kDataSize, 0);
1745 float *vAsFloat = reinterpret_cast<float *>(v.data());
1746
1747 vAsFloat[0u] = 1.0f;
1748 vAsFloat[1u] = 128.0f / 255.0f;
1749 vAsFloat[4u] = 64.0f / 255.0f;
1750 vAsFloat[5u] = 32.0f / 255.0f;
1751
1752 glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
1753 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
1754 glUniformBlockBinding(program, uniformBufferIndex, 0);
1755 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
1756 ASSERT_GL_NO_ERROR();
1757 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(255, 64, 128, 32), 5);
1758 }
1759
1760 // Regression test for a dirty bit bug in ANGLE. See http://crbug.com/792966
TEST_P(UniformBufferTest,SimpleBindingChange)1761 TEST_P(UniformBufferTest, SimpleBindingChange)
1762 {
1763 constexpr char kFragmentShader[] = R"(#version 300 es
1764 precision mediump float;
1765
1766 layout (std140) uniform color_ubo
1767 {
1768 vec4 color;
1769 };
1770
1771 out vec4 fragColor;
1772 void main()
1773 {
1774 fragColor = color;
1775 })";
1776
1777 // http://anglebug.com/40096481
1778 ANGLE_SKIP_TEST_IF(IsMac() && IsNVIDIA() && IsDesktopOpenGL());
1779
1780 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFragmentShader);
1781
1782 glBindAttribLocation(program, 0, essl3_shaders::PositionAttrib());
1783 glUseProgram(program);
1784 GLint uboIndex = glGetUniformBlockIndex(program, "color_ubo");
1785
1786 std::array<GLfloat, 12> vertices{{-1, -1, 0, 1, -1, 0, -1, 1, 0, 1, 1, 0}};
1787 GLBuffer vertexBuf;
1788 glBindBuffer(GL_ARRAY_BUFFER, vertexBuf);
1789 glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), vertices.data(),
1790 GL_STATIC_DRAW);
1791 glEnableVertexAttribArray(0);
1792 glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
1793
1794 std::array<GLshort, 12> indexData = {{0, 1, 2, 2, 1, 3, 0, 1, 2, 2, 1, 3}};
1795
1796 GLBuffer indexBuf;
1797 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
1798 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexData.size() * sizeof(GLshort), indexData.data(),
1799 GL_STATIC_DRAW);
1800
1801 // Bind a first buffer with red.
1802 GLBuffer uboBuf1;
1803 glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBuf1);
1804 glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatRed, GL_STATIC_DRAW);
1805 glUniformBlockBinding(program, uboIndex, 0);
1806
1807 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
1808
1809 // Bind a second buffer with green, updating the buffer binding.
1810 GLBuffer uboBuf2;
1811 glBindBufferBase(GL_UNIFORM_BUFFER, 1, uboBuf2);
1812 glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatGreen, GL_STATIC_DRAW);
1813 glUniformBlockBinding(program, uboIndex, 1);
1814
1815 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, reinterpret_cast<const GLvoid *>(12));
1816
1817 // Verify we get the second buffer.
1818 ASSERT_GL_NO_ERROR();
1819 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1820 }
1821
1822 // Regression test for a dirty bit bug in ANGLE. Same as above but for the indexed bindings.
TEST_P(UniformBufferTest,SimpleBufferChange)1823 TEST_P(UniformBufferTest, SimpleBufferChange)
1824 {
1825 constexpr char kFragmentShader[] = R"(#version 300 es
1826 precision mediump float;
1827
1828 layout (std140) uniform color_ubo
1829 {
1830 vec4 color;
1831 };
1832
1833 out vec4 fragColor;
1834 void main()
1835 {
1836 fragColor = color;
1837 })";
1838
1839 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFragmentShader);
1840
1841 glBindAttribLocation(program, 0, essl3_shaders::PositionAttrib());
1842 glUseProgram(program);
1843 GLint uboIndex = glGetUniformBlockIndex(program, "color_ubo");
1844
1845 std::array<GLfloat, 12> vertices{{-1, -1, 0, 1, -1, 0, -1, 1, 0, 1, 1, 0}};
1846 GLBuffer vertexBuf;
1847 glBindBuffer(GL_ARRAY_BUFFER, vertexBuf);
1848 glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), vertices.data(),
1849 GL_STATIC_DRAW);
1850 glEnableVertexAttribArray(0);
1851 glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
1852
1853 std::array<GLshort, 12> indexData = {{0, 1, 2, 2, 1, 3, 0, 1, 2, 2, 1, 3}};
1854
1855 GLBuffer indexBuf;
1856 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
1857 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexData.size() * sizeof(GLshort), indexData.data(),
1858 GL_STATIC_DRAW);
1859
1860 // Bind a first buffer with red.
1861 GLBuffer uboBuf1;
1862 glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBuf1);
1863 glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatRed, GL_STATIC_DRAW);
1864 glUniformBlockBinding(program, uboIndex, 0);
1865
1866 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
1867
1868 // Bind a second buffer to the same binding point (0). This should set to draw green.
1869 GLBuffer uboBuf2;
1870 glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBuf2);
1871 glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatGreen, GL_STATIC_DRAW);
1872
1873 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, reinterpret_cast<const GLvoid *>(12));
1874
1875 ASSERT_GL_NO_ERROR();
1876 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1877 }
1878
1879 // Tests a bug in the D3D11 back-end where re-creating the buffer storage should trigger a state
1880 // update in the State Manager class.
TEST_P(UniformBufferTest,DependentBufferChange)1881 TEST_P(UniformBufferTest, DependentBufferChange)
1882 {
1883 constexpr char kFragmentShader[] = R"(#version 300 es
1884 precision mediump float;
1885
1886 layout (std140) uniform color_ubo
1887 {
1888 vec4 color;
1889 };
1890
1891 out vec4 fragColor;
1892 void main()
1893 {
1894 fragColor = color;
1895 })";
1896
1897 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFragmentShader);
1898
1899 glBindAttribLocation(program, 0, essl3_shaders::PositionAttrib());
1900 glUseProgram(program);
1901 GLint uboIndex = glGetUniformBlockIndex(program, "color_ubo");
1902
1903 std::array<GLfloat, 12> vertices{{-1, -1, 0, 1, -1, 0, -1, 1, 0, 1, 1, 0}};
1904 GLBuffer vertexBuf;
1905 glBindBuffer(GL_ARRAY_BUFFER, vertexBuf);
1906 glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), vertices.data(),
1907 GL_STATIC_DRAW);
1908 glEnableVertexAttribArray(0);
1909 glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
1910
1911 std::array<GLshort, 6> indexData = {{0, 1, 2, 2, 1, 3}};
1912
1913 GLBuffer indexBuf;
1914 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
1915 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexData.size() * sizeof(GLshort), indexData.data(),
1916 GL_STATIC_DRAW);
1917
1918 GLBuffer ubo;
1919 glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo);
1920 glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F), &kFloatRed, GL_STATIC_DRAW);
1921 glUniformBlockBinding(program, uboIndex, 0);
1922
1923 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
1924 ASSERT_GL_NO_ERROR();
1925 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1926
1927 // Resize the buffer - triggers a re-allocation in the D3D11 back-end.
1928 std::vector<GLColor32F> bigData(128, kFloatGreen);
1929 glBufferData(GL_UNIFORM_BUFFER, sizeof(GLColor32F) * bigData.size(), bigData.data(),
1930 GL_STATIC_DRAW);
1931
1932 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
1933 ASSERT_GL_NO_ERROR();
1934 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1935 }
1936
1937 // Recreate WebGL conformance test conformance2/uniforms/large-uniform-buffers.html to test
1938 // regression in http://anglebug.com/42262055
TEST_P(UniformBufferTest,SizeOverMaxBlockSize)1939 TEST_P(UniformBufferTest, SizeOverMaxBlockSize)
1940 {
1941 constexpr char kFragmentShader[] = R"(#version 300 es
1942 precision mediump float;
1943
1944 layout (std140) uniform color_ubo
1945 {
1946 vec4 color;
1947 };
1948
1949 out vec4 fragColor;
1950 void main()
1951 {
1952 fragColor = color;
1953 })";
1954
1955 // Test crashes on Windows AMD OpenGL
1956 ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsOpenGL());
1957 // http://anglebug.com/42263922
1958 ANGLE_SKIP_TEST_IF(IsLinux() && IsAMD() && IsDesktopOpenGL());
1959
1960 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFragmentShader);
1961
1962 glBindAttribLocation(program, 0, essl3_shaders::PositionAttrib());
1963 glUseProgram(program);
1964 GLint uboIndex = glGetUniformBlockIndex(program, "color_ubo");
1965
1966 std::array<GLfloat, 12> vertices{{-1, -1, 0, 1, -1, 0, -1, 1, 0, 1, 1, 0}};
1967 GLBuffer vertexBuf;
1968 glBindBuffer(GL_ARRAY_BUFFER, vertexBuf);
1969 glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), vertices.data(),
1970 GL_STATIC_DRAW);
1971 glEnableVertexAttribArray(0);
1972 glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
1973
1974 std::array<GLshort, 6> indexData = {{0, 1, 2, 2, 1, 3}};
1975
1976 GLBuffer indexBuf;
1977 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
1978 glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexData.size() * sizeof(GLshort), indexData.data(),
1979 GL_STATIC_DRAW);
1980
1981 GLint uboDataSize = 0;
1982 glGetActiveUniformBlockiv(program, uboIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &uboDataSize);
1983 EXPECT_NE(uboDataSize, 0); // uniform block data size invalid
1984
1985 GLint64 maxUniformBlockSize;
1986 glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
1987
1988 GLBuffer uboBuf;
1989 std::vector<GLfloat> uboData;
1990 uboData.resize(maxUniformBlockSize * 2); // underlying data is twice the max block size
1991
1992 GLint offs0 = 0;
1993
1994 // Red
1995 uboData[offs0 + 0] = 1;
1996 uboData[offs0 + 1] = 0;
1997 uboData[offs0 + 2] = 0;
1998 uboData[offs0 + 3] = 1;
1999
2000 GLint offs1 = maxUniformBlockSize;
2001 GLint alignment = 0;
2002 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
2003 EXPECT_EQ(offs1 % alignment, 0);
2004
2005 // Green
2006 uboData[offs1 + 0] = 0;
2007 uboData[offs1 + 1] = 1;
2008 uboData[offs1 + 2] = 0;
2009 uboData[offs1 + 3] = 1;
2010
2011 glUniformBlockBinding(program, uboIndex, 0);
2012 glBindBufferBase(GL_UNIFORM_BUFFER, 0, uboBuf);
2013 glBufferData(GL_UNIFORM_BUFFER, uboData.size() * sizeof(GLfloat), uboData.data(),
2014 GL_STATIC_DRAW);
2015 ASSERT_GL_NO_ERROR(); // No errors from setup
2016
2017 // Draw lower triangle - should be red
2018 glBindBufferRange(GL_UNIFORM_BUFFER, 0, uboBuf, offs0 * sizeof(float), 4 * sizeof(float));
2019 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
2020 ASSERT_GL_NO_ERROR(); // No errors from draw
2021
2022 // Draw upper triangle - should be green
2023 glBindBufferRange(GL_UNIFORM_BUFFER, 0, uboBuf, offs1 * sizeof(float), 4 * sizeof(float));
2024 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT,
2025 reinterpret_cast<void *>(3 * sizeof(GLshort)));
2026 ASSERT_GL_NO_ERROR(); // No errors from draw
2027
2028 GLint width = getWindowWidth();
2029 GLint height = getWindowHeight();
2030 // Lower left should be red
2031 EXPECT_PIXEL_COLOR_EQ(width / 2 - 5, height / 2 - 5, GLColor::red);
2032 // Top right should be green
2033 EXPECT_PIXEL_COLOR_EQ(width / 2 + 5, height / 2 + 5, GLColor::green);
2034 }
2035
2036 // Test a uniform block where an array of row-major matrices is dynamically indexed.
TEST_P(UniformBufferTest,Std140UniformBlockWithDynamicallyIndexedRowMajorArray)2037 TEST_P(UniformBufferTest, Std140UniformBlockWithDynamicallyIndexedRowMajorArray)
2038 {
2039 // http://anglebug.com/42262481 , http://anglebug.com/40096480
2040 ANGLE_SKIP_TEST_IF(IsMac() && IsOpenGL() && (IsIntel() || IsAMD()));
2041
2042 constexpr char kFS[] =
2043 R"(#version 300 es
2044
2045 precision highp float;
2046 out vec4 my_FragColor;
2047
2048 uniform int u_zero;
2049
2050 layout(std140, row_major) uniform matrixBuffer {
2051 mat4 u_mats[1];
2052 };
2053
2054 void main() {
2055 float f = u_mats[u_zero + 0][2][1];
2056 my_FragColor = vec4(1.0 - f, f, 0.0, 1.0);
2057 })";
2058
2059 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
2060 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "matrixBuffer");
2061
2062 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
2063 const GLsizei kElementsPerMatrix = 16; // Each mat2 row gets padded into a vec4.
2064 const GLsizei kBytesPerElement = 4;
2065 const GLsizei kDataSize = kElementsPerMatrix * kBytesPerElement;
2066 std::vector<GLubyte> v(kDataSize, 0);
2067 float *vAsFloat = reinterpret_cast<float *>(v.data());
2068 // Write out this initializer to make it clearer what the matrix contains.
2069 float matrixData[kElementsPerMatrix] = {
2070 // clang-format off
2071 0.0f, 0.0f, 0.0f, 0.0f,
2072 0.0f, 0.0f, 1.0f, 0.0f,
2073 0.0f, 0.0f, 0.0f, 0.0f,
2074 0.0f, 0.0f, 0.0f, 0.0f,
2075 // clang-format on
2076 };
2077 for (int ii = 0; ii < kElementsPerMatrix; ++ii)
2078 {
2079 vAsFloat[ii] = matrixData[ii];
2080 }
2081 glBufferData(GL_UNIFORM_BUFFER, kDataSize, v.data(), GL_STATIC_DRAW);
2082 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
2083 glUniformBlockBinding(program, uniformBufferIndex, 0);
2084 GLint indexLoc = glGetUniformLocation(program, "u_zero");
2085 glUseProgram(program);
2086 glUniform1i(indexLoc, 0);
2087 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2088 ASSERT_GL_NO_ERROR();
2089 EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0, 255, 0, 255), 5);
2090 }
2091
2092 // Test with many uniform buffers work as expected.
TEST_P(UniformBufferTest,ManyBlocks)2093 TEST_P(UniformBufferTest, ManyBlocks)
2094 {
2095 // http://anglebug.com/42263608
2096 ANGLE_SKIP_TEST_IF(IsD3D11());
2097
2098 constexpr char kFS[] =
2099 R"(#version 300 es
2100
2101 precision highp float;
2102 out vec4 my_FragColor;
2103
2104 layout(std140) uniform uboBlock { vec4 color; } blocks[12];
2105
2106 void main()
2107 {
2108 vec4 color = vec4(0, 0, 0, 1);
2109 color += blocks[0].color;
2110 color += blocks[1].color;
2111 color += blocks[2].color;
2112 color += blocks[3].color;
2113 color += blocks[4].color;
2114 color += blocks[5].color;
2115 color += blocks[6].color;
2116 color += blocks[7].color;
2117 color += blocks[8].color;
2118 color += blocks[9].color;
2119 color += blocks[10].color;
2120 color += blocks[11].color;
2121 my_FragColor = vec4(color.rgb, 1.0);
2122 })";
2123
2124 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
2125 GLBuffer buffers[12];
2126 GLint bufferIndex[12];
2127 bufferIndex[0] = glGetUniformBlockIndex(program, "uboBlock[0]");
2128 bufferIndex[1] = glGetUniformBlockIndex(program, "uboBlock[1]");
2129 bufferIndex[2] = glGetUniformBlockIndex(program, "uboBlock[2]");
2130 bufferIndex[3] = glGetUniformBlockIndex(program, "uboBlock[3]");
2131 bufferIndex[4] = glGetUniformBlockIndex(program, "uboBlock[4]");
2132 bufferIndex[5] = glGetUniformBlockIndex(program, "uboBlock[5]");
2133 bufferIndex[6] = glGetUniformBlockIndex(program, "uboBlock[6]");
2134 bufferIndex[7] = glGetUniformBlockIndex(program, "uboBlock[7]");
2135 bufferIndex[8] = glGetUniformBlockIndex(program, "uboBlock[8]");
2136 bufferIndex[9] = glGetUniformBlockIndex(program, "uboBlock[9]");
2137 bufferIndex[10] = glGetUniformBlockIndex(program, "uboBlock[10]");
2138 bufferIndex[11] = glGetUniformBlockIndex(program, "uboBlock[11]");
2139
2140 std::vector<GLubyte> v(16, 0);
2141 float *vAsFloat = reinterpret_cast<float *>(v.data());
2142
2143 for (int i = 0; i < 12; ++i)
2144 {
2145 glBindBuffer(GL_UNIFORM_BUFFER, buffers[i]);
2146 vAsFloat[0] = (i + 1) / 255.0f;
2147 vAsFloat[1] = (i + 1) / 255.0f;
2148 vAsFloat[2] = (i + 1) / 255.0f;
2149 vAsFloat[3] = .0f;
2150
2151 glBufferData(GL_UNIFORM_BUFFER, v.size(), v.data(), GL_STATIC_DRAW);
2152
2153 glBindBufferBase(GL_UNIFORM_BUFFER, i, buffers[i]);
2154 glUniformBlockBinding(program, bufferIndex[i], i);
2155 }
2156
2157 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight());
2158 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2159
2160 // Modify buffer[1]
2161 glBindBuffer(GL_UNIFORM_BUFFER, buffers[1]);
2162
2163 vAsFloat[0] = 2 / 255.0f;
2164 vAsFloat[1] = 22 / 255.0f; // green channel increased by 20
2165 vAsFloat[2] = 2 / 255.0f;
2166 vAsFloat[3] = .0f;
2167
2168 glBufferData(GL_UNIFORM_BUFFER, v.size(), v.data(), GL_STATIC_DRAW);
2169
2170 glViewport(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight());
2171 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2172
2173 // First draw
2174 EXPECT_PIXEL_NEAR(0, 0, 78, 78, 78, 255, 2);
2175 // Second draw: green channel increased by 20
2176 EXPECT_PIXEL_NEAR(getWindowWidth() / 2, 0, 78, 98, 78, 255, 2);
2177 }
2178
2179 // These suite cases test the uniform blocks with a large array member. Unlike other uniform
2180 // blocks that will be translated to cbuffer type on D3D backend, we will tranlate these
2181 // uniform blocks to StructuredBuffer for slow fxc compile performance issue with dynamic
2182 // uniform indexing, angleproject/3682.
2183 class UniformBlockWithOneLargeArrayMemberTest : public ANGLETest<>
2184 {
2185 protected:
UniformBlockWithOneLargeArrayMemberTest()2186 UniformBlockWithOneLargeArrayMemberTest()
2187 {
2188 setWindowWidth(128);
2189 setWindowHeight(128);
2190 setConfigRedBits(8);
2191 setConfigGreenBits(8);
2192 setConfigBlueBits(8);
2193 setConfigAlphaBits(8);
2194 }
2195
testSetUp()2196 void testSetUp() override
2197 {
2198 glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &mMaxUniformBlockSize);
2199 // Ensure that shader uniform block does not exceed MAX_UNIFORM_BLOCK_SIZE limit.
2200 if (mMaxUniformBlockSize >= 16384 && mMaxUniformBlockSize < 32768)
2201 {
2202 mArraySize1 = 128;
2203 mArraySize2 = 8;
2204 mDivisor1 = 128;
2205 mDivisor2 = 32;
2206 mDivisor3 = 16;
2207 }
2208 else if (mMaxUniformBlockSize >= 32768 && mMaxUniformBlockSize < 65536)
2209 {
2210 mArraySize1 = 256;
2211 mArraySize2 = 16;
2212 mDivisor1 = 64;
2213 mDivisor2 = 16;
2214 mDivisor3 = 8;
2215 }
2216 else
2217 {
2218 mArraySize1 = 512;
2219 mArraySize2 = 32;
2220 mDivisor1 = 32;
2221 mDivisor2 = 8;
2222 mDivisor3 = 4;
2223 }
2224
2225 glGenBuffers(1, &mUniformBuffer);
2226 ASSERT_GL_NO_ERROR();
2227 }
2228
testTearDown()2229 void testTearDown() override { glDeleteBuffers(1, &mUniformBuffer); }
2230
generateArraySizeAndDivisorsDeclaration(std::ostringstream & out,bool hasArraySize2,bool hasDivisor2,bool hasDivisor3)2231 void generateArraySizeAndDivisorsDeclaration(std::ostringstream &out,
2232 bool hasArraySize2,
2233 bool hasDivisor2,
2234 bool hasDivisor3)
2235 {
2236 if (hasArraySize2)
2237 {
2238 out << "const uint arraySize1 = " << mArraySize1 << "u;\n";
2239 out << "const uint arraySize2 = " << mArraySize2 << "u;\n";
2240 }
2241 else
2242 {
2243 out << "const uint arraySize = " << mArraySize1 << "u;\n";
2244 }
2245
2246 if (hasDivisor2)
2247 {
2248 out << "const uint divisor1 = " << mDivisor1 << "u;\n";
2249 out << "const uint divisor2 = " << mDivisor2 << "u;\n";
2250 }
2251 else
2252 {
2253 out << "const uint divisor = " << mDivisor1 << "u;\n";
2254 }
2255 if (hasDivisor3)
2256 {
2257 out << "const uint divisor3 = " << mDivisor3 << "u;\n";
2258 }
2259 }
getArraySize()2260 GLuint getArraySize() { return mArraySize1; }
getArraySize2()2261 GLuint getArraySize2() { return mArraySize2; }
2262
setArrayValues(std::vector<GLfloat> & floatData,GLuint beginIndex,GLuint endIndex,GLuint stride,GLuint firstElementOffset,GLuint firstEleVecCount,GLuint firstEleVecComponents,float x1,float y1,float z1,float w1,GLuint secondElementOffset=0,GLuint secondEleVecCount=0,GLuint secondEleVecComponents=0,float x2=0.0f,float y2=0.0f,float z2=0.0f,float w2=0.0f)2263 void setArrayValues(std::vector<GLfloat> &floatData,
2264 GLuint beginIndex,
2265 GLuint endIndex,
2266 GLuint stride,
2267 GLuint firstElementOffset,
2268 GLuint firstEleVecCount,
2269 GLuint firstEleVecComponents,
2270 float x1,
2271 float y1,
2272 float z1,
2273 float w1,
2274 GLuint secondElementOffset = 0,
2275 GLuint secondEleVecCount = 0,
2276 GLuint secondEleVecComponents = 0,
2277 float x2 = 0.0f,
2278 float y2 = 0.0f,
2279 float z2 = 0.0f,
2280 float w2 = 0.0f)
2281 {
2282 for (GLuint i = beginIndex; i < endIndex; i++)
2283 {
2284 for (GLuint j = 0; j < firstEleVecCount; j++)
2285 {
2286 if (firstEleVecComponents > 3)
2287 {
2288 floatData[i * stride + firstElementOffset + 4 * j + 3] = w1;
2289 }
2290 if (firstEleVecComponents > 2)
2291 {
2292 floatData[i * stride + firstElementOffset + 4 * j + 2] = z1;
2293 }
2294 if (firstEleVecComponents > 1)
2295 {
2296 floatData[i * stride + firstElementOffset + 4 * j + 1] = y1;
2297 }
2298 floatData[i * stride + firstElementOffset + 4 * j] = x1;
2299 }
2300
2301 for (GLuint k = 0; k < secondEleVecCount; k++)
2302 {
2303 if (secondEleVecComponents > 3)
2304 {
2305 floatData[i * stride + secondElementOffset + 4 * k + 3] = w2;
2306 }
2307 if (secondEleVecComponents > 2)
2308 {
2309 floatData[i * stride + secondElementOffset + 4 * k + 2] = z2;
2310 }
2311 if (secondEleVecComponents > 1)
2312 {
2313 floatData[i * stride + secondElementOffset + 4 * k + 1] = y2;
2314 }
2315 floatData[i * stride + secondElementOffset + 4 * k] = x2;
2316 }
2317 }
2318 }
2319
checkResults(const GLColor & firstQuarter,const GLColor & secondQuarter,const GLColor & thirdQuarter,const GLColor & fourthQuarter)2320 void checkResults(const GLColor &firstQuarter,
2321 const GLColor &secondQuarter,
2322 const GLColor &thirdQuarter,
2323 const GLColor &fourthQuarter)
2324 {
2325 for (GLuint i = 0; i < kPositionCount; i++)
2326 {
2327 if (positionToTest[i][1] >= 0 && positionToTest[i][1] < 32)
2328 {
2329 EXPECT_PIXEL_COLOR_EQ(positionToTest[i][0], positionToTest[i][1], firstQuarter);
2330 }
2331 else if (positionToTest[i][1] >= 32 && positionToTest[i][1] < 64)
2332 {
2333 EXPECT_PIXEL_COLOR_EQ(positionToTest[i][0], positionToTest[i][1], secondQuarter);
2334 }
2335 else if (positionToTest[i][1] >= 64 && positionToTest[i][1] < 96)
2336 {
2337 EXPECT_PIXEL_COLOR_EQ(positionToTest[i][0], positionToTest[i][1], thirdQuarter);
2338 }
2339 else
2340 {
2341 EXPECT_PIXEL_COLOR_EQ(positionToTest[i][0], positionToTest[i][1], fourthQuarter);
2342 }
2343 }
2344 }
2345
2346 GLuint mUniformBuffer;
2347 GLint64 mMaxUniformBlockSize;
2348 GLuint mArraySize1;
2349 GLuint mArraySize2;
2350 GLuint mDivisor1;
2351 GLuint mDivisor2;
2352 GLuint mDivisor3;
2353
2354 static constexpr GLuint kVectorPerMat = 4;
2355 static constexpr GLuint kFloatPerVector = 4;
2356 static constexpr GLuint kPositionCount = 12;
2357 static constexpr unsigned int positionToTest[kPositionCount][2] = {
2358 {0, 0}, {75, 0}, {98, 13}, {31, 31}, {0, 32}, {65, 33},
2359 {23, 54}, {63, 63}, {0, 64}, {43, 86}, {53, 100}, {127, 127}};
2360 };
2361
2362 // Test uniform block whose member is structure type, which contains a mat4 member.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsStruct)2363 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsStruct)
2364 {
2365 std::ostringstream stream;
2366 generateArraySizeAndDivisorsDeclaration(stream, false, true, false);
2367 const std::string &kFS =
2368 "#version 300 es\n"
2369 "precision highp float;\n" +
2370 stream.str() +
2371 "out vec4 my_FragColor;\n"
2372 "struct S { mat4 color;};\n"
2373 "layout(std140) uniform buffer { S s[arraySize]; };\n"
2374 "void main()\n"
2375 "{\n"
2376 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
2377 " uint index = coord.x + coord.y * 128u;\n"
2378 " uint index_x = index / divisor1;\n"
2379 " uint index_y = (index % divisor1) / divisor2;\n"
2380 " my_FragColor = s[index_x].color[index_y];\n"
2381 "}\n";
2382
2383 GLint blockSize;
2384 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
2385 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
2386 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
2387
2388 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
2389 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
2390
2391 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
2392 glUniformBlockBinding(program, uniformBufferIndex, 0);
2393
2394 const GLuint arraySize = getArraySize();
2395 const GLuint floatCount = arraySize * kVectorPerMat * kFloatPerVector;
2396 std::vector<GLfloat> floatData(floatCount, 0.0f);
2397
2398 setArrayValues(floatData, 0, arraySize, 16, 0, 4, 4, 0.0f, 0.0f, 1.0f, 1.0f);
2399 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
2400 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2401 checkResults(GLColor::blue, GLColor::blue, GLColor::blue, GLColor::blue);
2402
2403 setArrayValues(floatData, 0, arraySize, 16, 0, 4, 4, 0.0f, 1.0f, 0.0f, 1.0f);
2404 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
2405 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2406 checkResults(GLColor::green, GLColor::green, GLColor::green, GLColor::green);
2407
2408 setArrayValues(floatData, arraySize / 4, arraySize / 2, 16, 0, 4, 4, 1.0f, 0.0f, 0.0f, 1.0f);
2409 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
2410 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2411 checkResults(GLColor::green, GLColor::red, GLColor::green, GLColor::green);
2412 }
2413
2414 // Test instanced uniform block whose member is structure type, which contains a mat4 member.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsStructAndInstanced)2415 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsStructAndInstanced)
2416 {
2417 std::ostringstream stream;
2418 generateArraySizeAndDivisorsDeclaration(stream, false, true, false);
2419 const std::string &kFS =
2420 "#version 300 es\n"
2421 "precision highp float;\n" +
2422 stream.str() +
2423 "out vec4 my_FragColor;\n"
2424 "struct S { mat4 color;};\n"
2425 "layout(std140) uniform buffer { S s[arraySize]; } instance;\n"
2426 "void main()\n"
2427 "{\n"
2428 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
2429 " uint index = coord.x + coord.y * 128u;\n"
2430 " uint index_x = index / divisor1;\n"
2431 " uint index_y = (index % divisor1) / divisor2;\n"
2432 " my_FragColor = instance.s[index_x].color[index_y];\n"
2433 "}\n";
2434
2435 GLint blockSize;
2436 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
2437 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
2438 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
2439
2440 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
2441 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
2442
2443 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
2444 glUniformBlockBinding(program, uniformBufferIndex, 0);
2445
2446 const GLuint arraySize = getArraySize();
2447 const GLuint floatCount = arraySize * kVectorPerMat * kFloatPerVector;
2448 std::vector<GLfloat> floatData(floatCount, 0.0f);
2449
2450 setArrayValues(floatData, 0, arraySize, 16, 0, 4, 4, 0.0f, 0.0f, 1.0f, 1.0f);
2451 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
2452 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2453 checkResults(GLColor::blue, GLColor::blue, GLColor::blue, GLColor::blue);
2454
2455 setArrayValues(floatData, 0, arraySize, 16, 0, 4, 4, 0.0f, 1.0f, 0.0f, 1.0f);
2456 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
2457 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2458 checkResults(GLColor::green, GLColor::green, GLColor::green, GLColor::green);
2459
2460 setArrayValues(floatData, arraySize / 4, arraySize / 2, 16, 0, 4, 4, 1.0f, 0.0f, 0.0f, 1.0f);
2461 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
2462 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2463 checkResults(GLColor::green, GLColor::red, GLColor::green, GLColor::green);
2464 }
2465
2466 // Test instanced uniform block array whose member is structure type, which contains a mat4 member.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsStructAndInstancedArray)2467 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsStructAndInstancedArray)
2468 {
2469 std::ostringstream stream;
2470 generateArraySizeAndDivisorsDeclaration(stream, false, true, false);
2471 const std::string &kFS =
2472 "#version 300 es\n"
2473 "precision highp float;\n" +
2474 stream.str() +
2475 "out vec4 my_FragColor;\n"
2476 "struct S { mat4 color;};\n"
2477 "layout(std140) uniform buffer { S s[arraySize]; } instance[2];\n"
2478 "void main()\n"
2479 "{\n"
2480 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
2481 " uint index = coord.x + coord.y * 128u;\n"
2482 " uint index_x = index / divisor1;\n"
2483 " uint index_y = (index % divisor1) / divisor2;\n"
2484 " my_FragColor = instance[0].s[index_x].color[index_y] + "
2485 "instance[1].s[index_x].color[index_y];\n"
2486 "}\n";
2487
2488 GLint blockSize0, blockSize1;
2489 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
2490 GLint uniformBufferIndex0 = glGetUniformBlockIndex(program, "buffer[0]");
2491 GLint uniformBufferIndex1 = glGetUniformBlockIndex(program, "buffer[1]");
2492 glGetActiveUniformBlockiv(program, uniformBufferIndex0, GL_UNIFORM_BLOCK_DATA_SIZE,
2493 &blockSize0);
2494 glGetActiveUniformBlockiv(program, uniformBufferIndex1, GL_UNIFORM_BLOCK_DATA_SIZE,
2495 &blockSize1);
2496
2497 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
2498 glBufferData(GL_UNIFORM_BUFFER, blockSize0, nullptr, GL_STATIC_DRAW);
2499
2500 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
2501 glUniformBlockBinding(program, uniformBufferIndex0, 0);
2502
2503 const GLuint arraySize = getArraySize();
2504 const GLuint floatCount = arraySize * kVectorPerMat * kFloatPerVector;
2505 std::vector<GLfloat> floatData0(floatCount, 0.0f);
2506 std::vector<GLfloat> floatData1(floatCount, 0.0f);
2507
2508 setArrayValues(floatData0, 0, arraySize, 16, 0, 4, 4, 0.0f, 0.0f, 1.0f, 1.0f);
2509 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData0.data());
2510
2511 GLBuffer uniformBuffer1;
2512 glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer1);
2513 glBufferData(GL_UNIFORM_BUFFER, blockSize1, nullptr, GL_STATIC_DRAW);
2514
2515 glBindBufferBase(GL_UNIFORM_BUFFER, 1, uniformBuffer1);
2516 glUniformBlockBinding(program, uniformBufferIndex0, 1);
2517
2518 setArrayValues(floatData1, 0, arraySize, 16, 0, 4, 4, 0.0f, 1.0f, 0.0f, 0.0f);
2519 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData1.data());
2520 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2521 checkResults(GLColor::cyan, GLColor::cyan, GLColor::cyan, GLColor::cyan);
2522
2523 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
2524 setArrayValues(floatData0, 0, arraySize, 16, 0, 4, 4, 1.0f, 0.0f, 0.0f, 1.0f);
2525 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData0.data());
2526 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2527 checkResults(GLColor::yellow, GLColor::yellow, GLColor::yellow, GLColor::yellow);
2528
2529 glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer1);
2530 setArrayValues(floatData1, arraySize / 4, arraySize / 2, 16, 0, 4, 4, 0.0f, 0.0f, 1.0f, 0.0f);
2531 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData1.data());
2532 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2533 checkResults(GLColor::yellow, GLColor::magenta, GLColor::yellow, GLColor::yellow);
2534 }
2535
2536 // Test uniform block whose member is structure type, which contains a mat4 member and a float
2537 // member.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsMixStructMat4AndFloat)2538 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsMixStructMat4AndFloat)
2539 {
2540 std::ostringstream stream;
2541 generateArraySizeAndDivisorsDeclaration(stream, false, true, false);
2542 const std::string &kFS =
2543 "#version 300 es\n"
2544 "precision highp float;\n" +
2545 stream.str() +
2546 "out vec4 my_FragColor;\n"
2547 "struct S { mat4 color; float factor; };\n"
2548 "layout(std140) uniform buffer { S s[arraySize]; };\n"
2549 "void main()\n"
2550 "{\n"
2551 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
2552 " uint index = coord.x + coord.y * 128u;\n"
2553 " uint index_x = index / divisor1;\n"
2554 " uint index_y = (index % divisor1) / divisor2;\n"
2555 " my_FragColor = s[index_x].factor * s[index_x].color[index_y];\n"
2556 "}\n";
2557
2558 GLint blockSize;
2559 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
2560 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
2561 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
2562
2563 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
2564 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
2565
2566 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
2567 glUniformBlockBinding(program, uniformBufferIndex, 0);
2568
2569 // The member s is an array of S structures, each element of s should be rounded up
2570 // to the base alignment of a vec4 according to std140 storage layout rules.
2571 const GLuint arraySize = getArraySize();
2572 const GLuint floatCount = arraySize * (kVectorPerMat * kFloatPerVector + kFloatPerVector);
2573 std::vector<GLfloat> floatData(floatCount, 0.0f);
2574 const size_t strideofFloatCount = kVectorPerMat * kFloatPerVector + kFloatPerVector;
2575
2576 setArrayValues(floatData, 0, arraySize, strideofFloatCount, 0, 4, 4, 0.0f, 0.0f, 0.5f, 0.5f, 16,
2577 1, 1, 2.0f, 0.0f, 0.0f, 0.0f);
2578 glBufferSubData(GL_UNIFORM_BUFFER, 0,
2579 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
2580 floatData.data());
2581 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2582 checkResults(GLColor::blue, GLColor::blue, GLColor::blue, GLColor::blue);
2583
2584 setArrayValues(floatData, 0, arraySize, strideofFloatCount, 0, 4, 4, 0.0f, 0.5f, 0.0f, 0.5f, 16,
2585 1, 1, 2.0f, 0.0f, 0.0f, 0.0f);
2586 glBufferSubData(GL_UNIFORM_BUFFER, 0,
2587 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
2588 floatData.data());
2589 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2590 checkResults(GLColor::green, GLColor::green, GLColor::green, GLColor::green);
2591
2592 setArrayValues(floatData, arraySize / 4, arraySize / 2, strideofFloatCount, 0, 4, 4, 0.5f, 0.0f,
2593 0.0f, 0.5f, 16, 1, 1, 2.0f, 0.0f, 0.0f, 0.0f);
2594 glBufferSubData(GL_UNIFORM_BUFFER, 0,
2595 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
2596 floatData.data());
2597 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2598 checkResults(GLColor::green, GLColor::red, GLColor::green, GLColor::green);
2599 }
2600
2601 // Test uniform block whose member is structure type, which contains a vec2 member and a vec3
2602 // member.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsMixStructVec2AndVec3)2603 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsMixStructVec2AndVec3)
2604 {
2605 std::ostringstream stream;
2606 generateArraySizeAndDivisorsDeclaration(stream, false, false, false);
2607 const std::string &kFS =
2608 "#version 300 es\n"
2609 "precision highp float;\n" +
2610 stream.str() +
2611 "out vec4 my_FragColor;\n"
2612 "struct S { vec2 color1; vec3 color2; };\n"
2613 "layout(std140) uniform buffer { S s[arraySize]; };\n"
2614 "void main()\n"
2615 "{\n"
2616 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
2617 " uint index = (coord.x + coord.y * 128u) / divisor;\n"
2618 " my_FragColor = vec4(s[index].color1, s[index].color2.xy);\n"
2619 "}\n";
2620
2621 GLint blockSize;
2622 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
2623 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
2624 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
2625
2626 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
2627 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
2628
2629 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
2630 glUniformBlockBinding(program, uniformBufferIndex, 0);
2631
2632 // The base alignment of "color2" is vec4.
2633 const GLuint arraySize = getArraySize();
2634 const GLuint floatCount = arraySize * 2 * kFloatPerVector;
2635 std::vector<GLfloat> floatData(floatCount, 0.0f);
2636 const size_t strideofFloatCount = 2 * kFloatPerVector;
2637
2638 setArrayValues(floatData, 0, arraySize, strideofFloatCount, 0, 1, 2, 1.0f, 1.0f, 0.0f, 0.0f, 4,
2639 1, 3, 1.0f, 1.0f, 0.0f, 0.0f);
2640 glBufferSubData(GL_UNIFORM_BUFFER, 0,
2641 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
2642 floatData.data());
2643 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2644 checkResults(GLColor::white, GLColor::white, GLColor::white, GLColor::white);
2645
2646 setArrayValues(floatData, 0, arraySize, strideofFloatCount, 0, 1, 2, 1.0f, 0.0f, 0.0f, 0.0f, 4,
2647 1, 3, 0.0f, 1.0f, 0.0f, 0.0f);
2648 glBufferSubData(GL_UNIFORM_BUFFER, 0,
2649 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
2650 floatData.data());
2651 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2652 checkResults(GLColor::red, GLColor::red, GLColor::red, GLColor::red);
2653
2654 setArrayValues(floatData, arraySize / 4, arraySize / 2, strideofFloatCount, 0, 1, 2, 0.0f, 0.0f,
2655 0.0f, 0.0f, 4, 1, 3, 1.0f, 1.0f, 0.0f, 0.0f);
2656 glBufferSubData(GL_UNIFORM_BUFFER, 0,
2657 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
2658 floatData.data());
2659 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2660 checkResults(GLColor::red, GLColor::blue, GLColor::red, GLColor::red);
2661 }
2662
2663 // Test uniform block whose member is structure type, which contains a float member and a vec3
2664 // member.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsMixStructFloatAndVec3)2665 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsMixStructFloatAndVec3)
2666 {
2667 std::ostringstream stream;
2668 generateArraySizeAndDivisorsDeclaration(stream, false, false, false);
2669 const std::string &kFS =
2670 "#version 300 es\n"
2671 "precision highp float;\n" +
2672 stream.str() +
2673 "out vec4 my_FragColor;\n"
2674 "struct S { float color1; vec3 color2; };\n"
2675 "layout(std140) uniform buffer { S s[arraySize]; };\n"
2676 "void main()\n"
2677 "{\n"
2678 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
2679 " uint index = (coord.x + coord.y * 128u) / divisor;\n"
2680 " my_FragColor = vec4(s[index].color1, s[index].color2);\n"
2681 "}\n";
2682
2683 GLint blockSize;
2684 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
2685 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
2686 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
2687
2688 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
2689 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
2690
2691 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
2692 glUniformBlockBinding(program, uniformBufferIndex, 0);
2693
2694 // The base alignment of "color2" is vec4.
2695 const GLuint arraySize = getArraySize();
2696 const GLuint floatCount = arraySize * 2 * kFloatPerVector;
2697 std::vector<GLfloat> floatData(floatCount, 0.0f);
2698 const size_t strideofFloatCount = 2 * kFloatPerVector;
2699
2700 setArrayValues(floatData, 0, arraySize, strideofFloatCount, 0, 1, 1, 1.0f, 0.0f, 0.0f, 0.0f, 4,
2701 1, 3, 1.0f, 1.0f, 1.0f, 0.0f);
2702 glBufferSubData(GL_UNIFORM_BUFFER, 0,
2703 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
2704 floatData.data());
2705 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2706 checkResults(GLColor::white, GLColor::white, GLColor::white, GLColor::white);
2707
2708 setArrayValues(floatData, 0, arraySize, strideofFloatCount, 0, 1, 1, 1.0f, 0.0f, 0.0f, 0.0f, 4,
2709 1, 3, 0.0f, 0.0f, 1.0f, 0.0f);
2710 glBufferSubData(GL_UNIFORM_BUFFER, 0,
2711 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
2712 floatData.data());
2713 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2714 checkResults(GLColor::red, GLColor::red, GLColor::red, GLColor::red);
2715
2716 setArrayValues(floatData, arraySize / 4, arraySize / 2, strideofFloatCount, 0, 1, 1, 0.0f, 0.0f,
2717 0.0f, 0.0f, 4, 1, 3, 0.0f, 1.0f, 1.0f, 0.0f);
2718 glBufferSubData(GL_UNIFORM_BUFFER, 0,
2719 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
2720 floatData.data());
2721 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2722 checkResults(GLColor::red, GLColor::blue, GLColor::red, GLColor::red);
2723 }
2724
2725 // Test uniform block whose member is structure type, which contains a vec3 member and a float
2726 // member.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsMixStructVec3AndFloat)2727 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsMixStructVec3AndFloat)
2728 {
2729 std::ostringstream stream;
2730 generateArraySizeAndDivisorsDeclaration(stream, false, false, false);
2731 const std::string &kFS =
2732 "#version 300 es\n"
2733 "precision highp float;\n" +
2734 stream.str() +
2735 "out vec4 my_FragColor;\n"
2736 "struct S { vec3 color1; float color2; };\n"
2737 "layout(std140) uniform buffer { S s[arraySize]; };\n"
2738 "void main()\n"
2739 "{\n"
2740 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
2741 " uint index = (coord.x + coord.y * 128u) / divisor;\n"
2742 " my_FragColor = vec4(s[index].color2, s[index].color1);\n"
2743 "}\n";
2744
2745 GLint blockSize;
2746 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
2747 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
2748 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
2749
2750 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
2751 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
2752
2753 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
2754 glUniformBlockBinding(program, uniformBufferIndex, 0);
2755
2756 const GLuint arraySize = getArraySize();
2757 const GLuint floatCount = arraySize * kFloatPerVector;
2758 std::vector<GLfloat> floatData(floatCount, 0.0f);
2759 const size_t strideofFloatCount = kFloatPerVector;
2760
2761 setArrayValues(floatData, 0, arraySize, strideofFloatCount, 0, 1, 3, 1.0f, 1.0f, 1.0f, 0.0f, 3,
2762 1, 1, 1.0f, 0.0f, 0.0f, 0.0f);
2763 glBufferSubData(GL_UNIFORM_BUFFER, 0,
2764 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
2765 floatData.data());
2766 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2767 checkResults(GLColor::white, GLColor::white, GLColor::white, GLColor::white);
2768
2769 setArrayValues(floatData, 0, arraySize, strideofFloatCount, 0, 1, 3, 0.0f, 0.0f, 1.0f, 0.0f, 3,
2770 1, 1, 1.0f, 0.0f, 0.0f, 0.0f);
2771 glBufferSubData(GL_UNIFORM_BUFFER, 0,
2772 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
2773 floatData.data());
2774 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2775 checkResults(GLColor::red, GLColor::red, GLColor::red, GLColor::red);
2776
2777 setArrayValues(floatData, arraySize / 4, arraySize / 2, strideofFloatCount, 0, 1, 3, 0.0f, 1.0f,
2778 1.0f, 0.0f, 3, 1, 1, 0.0f, 0.0f, 0.0f, 0.0f);
2779 glBufferSubData(GL_UNIFORM_BUFFER, 0,
2780 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
2781 floatData.data());
2782 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2783 checkResults(GLColor::red, GLColor::blue, GLColor::red, GLColor::red);
2784 }
2785
2786 // Test two uniform blocks with large structure array member are in the same program, and they
2787 // share the same uniform buffer.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,TwoUniformBlocksInSameProgram)2788 TEST_P(UniformBlockWithOneLargeArrayMemberTest, TwoUniformBlocksInSameProgram)
2789 {
2790 std::ostringstream stream;
2791 generateArraySizeAndDivisorsDeclaration(stream, true, true, true);
2792 const std::string &kFS =
2793 "#version 300 es\n"
2794 "precision highp float;\n" +
2795 stream.str() +
2796 "out vec4 my_FragColor;\n"
2797 "struct S { mat4 color;};\n"
2798 "layout(std140) uniform buffer1 { S s1[arraySize1]; };\n"
2799 "layout(std140) uniform buffer2 { S s2[arraySize2]; };\n"
2800 "void main()\n"
2801 "{\n"
2802 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
2803 " uint index = coord.x + coord.y * 128u;\n"
2804 " uint index_x1 = index / divisor1;\n"
2805 " uint index_y1 = (index % divisor1) / divisor2;\n"
2806 " uint index_x2 = coord.x / divisor3;\n"
2807 " uint index_y2 = coord.x % 4u;\n"
2808 " my_FragColor = s1[index_x1].color[index_y1] + s2[index_x2].color[index_y2];\n"
2809 "}\n";
2810
2811 GLint blockSize1, blockSize2;
2812 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
2813 GLint uniformBufferIndex1 = glGetUniformBlockIndex(program, "buffer1");
2814 GLint uniformBufferIndex2 = glGetUniformBlockIndex(program, "buffer2");
2815 glGetActiveUniformBlockiv(program, uniformBufferIndex1, GL_UNIFORM_BLOCK_DATA_SIZE,
2816 &blockSize1);
2817 glGetActiveUniformBlockiv(program, uniformBufferIndex2, GL_UNIFORM_BLOCK_DATA_SIZE,
2818 &blockSize2);
2819
2820 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
2821 glBufferData(GL_UNIFORM_BUFFER, blockSize1 + blockSize2, nullptr, GL_STATIC_DRAW);
2822
2823 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, 0, blockSize2);
2824 glUniformBlockBinding(program, uniformBufferIndex2, 0);
2825 glBindBufferRange(GL_UNIFORM_BUFFER, 1, mUniformBuffer, blockSize2, blockSize1);
2826 glUniformBlockBinding(program, uniformBufferIndex1, 1);
2827
2828 const GLuint arraySize1 = getArraySize();
2829 const GLuint arraySize2 = getArraySize2();
2830 const GLuint floatCount1 = arraySize1 * kVectorPerMat * kFloatPerVector;
2831 const GLuint floatCount2 = arraySize2 * kVectorPerMat * kFloatPerVector;
2832 const GLuint floatCount = floatCount1 + floatCount2;
2833 std::vector<GLfloat> floatData(floatCount, 0.0f);
2834
2835 setArrayValues(floatData, arraySize2, arraySize1 + arraySize2, 16, 0, 4, 4, 0.0f, 0.0f, 1.0f,
2836 1.0f);
2837 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount2 * sizeof(GLfloat), &floatData[0]);
2838 glBufferSubData(GL_UNIFORM_BUFFER, blockSize2, floatCount1 * sizeof(GLfloat),
2839 &floatData[floatCount2]);
2840 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2841 checkResults(GLColor::blue, GLColor::blue, GLColor::blue, GLColor::blue);
2842
2843 setArrayValues(floatData, 0, arraySize2, 16, 0, 4, 4, 0.0f, 1.0f, 0.0f, 0.0f);
2844 setArrayValues(floatData, arraySize1 / 4, arraySize2 + arraySize1 / 2, 16, 0, 4, 4, 1.0f, 0.0f,
2845 0.0f, 1.0f);
2846 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount2 * sizeof(GLfloat), &floatData[0]);
2847 glBufferSubData(GL_UNIFORM_BUFFER, blockSize2 + floatCount1 * sizeof(GLfloat) / 4,
2848 floatCount1 * sizeof(GLfloat) / 4, &floatData[floatCount2 + floatCount1 / 4]);
2849 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2850 checkResults(GLColor::cyan, GLColor::yellow, GLColor::cyan, GLColor::cyan);
2851 }
2852
2853 // Test a uniform block with large struct array member and a uniform block with small
2854 // struct array member in different programs, but they share the same uniform buffer.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,TwoUniformBlocksInDiffProgram)2855 TEST_P(UniformBlockWithOneLargeArrayMemberTest, TwoUniformBlocksInDiffProgram)
2856 {
2857 std::ostringstream stream1;
2858 std::ostringstream stream2;
2859 generateArraySizeAndDivisorsDeclaration(stream1, false, true, false);
2860 generateArraySizeAndDivisorsDeclaration(stream2, false, false, false);
2861
2862 const std::string &kFS1 =
2863 "#version 300 es\n"
2864 "precision highp float;\n" +
2865 stream1.str() +
2866 "out vec4 my_FragColor;\n"
2867 "struct S { mat4 color;};\n"
2868 "layout(std140) uniform buffer { S s[arraySize]; };\n"
2869 "void main()\n"
2870 "{\n"
2871 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
2872 " uint index = coord.x + coord.y * 128u;\n"
2873 " uint index_x = index / divisor1;\n"
2874 " uint index_y = (index % divisor1) / divisor2;\n"
2875 " my_FragColor = s[index_x].color[index_y];\n"
2876 "}\n";
2877
2878 const std::string &kFS2 =
2879 "#version 300 es\n"
2880 "precision highp float;\n" +
2881 stream2.str() +
2882 "out vec4 my_FragColor;\n"
2883 "struct S { mat4 color;};\n"
2884 "layout(std140) uniform buffer { S s[arraySize]; };\n"
2885 "void main()\n"
2886 "{\n"
2887 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
2888 " uint index_x = coord.x / divisor;\n"
2889 " uint index_y = coord.x % 4u;\n"
2890 " my_FragColor = s[index_x].color[index_y];\n"
2891 "}\n";
2892
2893 GLint blockSize1, blockSize2;
2894 ANGLE_GL_PROGRAM(program1, essl3_shaders::vs::Simple(), kFS1.c_str());
2895 ANGLE_GL_PROGRAM(program2, essl3_shaders::vs::Simple(), kFS2.c_str());
2896 GLint uniformBufferIndex1 = glGetUniformBlockIndex(program1, "buffer");
2897 GLint uniformBufferIndex2 = glGetUniformBlockIndex(program2, "buffer");
2898 glGetActiveUniformBlockiv(program1, uniformBufferIndex1, GL_UNIFORM_BLOCK_DATA_SIZE,
2899 &blockSize1);
2900 glGetActiveUniformBlockiv(program2, uniformBufferIndex2, GL_UNIFORM_BLOCK_DATA_SIZE,
2901 &blockSize2);
2902
2903 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
2904 glBufferData(GL_UNIFORM_BUFFER, std::max(blockSize1, blockSize2), nullptr, GL_STATIC_DRAW);
2905
2906 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, 0, blockSize2);
2907 glUniformBlockBinding(program2, uniformBufferIndex2, 0);
2908 glBindBufferRange(GL_UNIFORM_BUFFER, 1, mUniformBuffer, 0, blockSize1);
2909 glUniformBlockBinding(program1, uniformBufferIndex1, 1);
2910
2911 const GLuint arraySize1 = getArraySize();
2912 const GLuint arraySize2 = getArraySize2();
2913 const GLuint floatCount1 = arraySize1 * kVectorPerMat * kFloatPerVector;
2914 const GLuint floatCount2 = arraySize2 * kVectorPerMat * kFloatPerVector;
2915 const GLuint floatCount = floatCount1;
2916 std::vector<GLfloat> floatData(floatCount, 0.0f);
2917
2918 setArrayValues(floatData, 0, arraySize1, 16, 0, 4, 4, 0.0f, 0.0f, 1.0f, 1.0f);
2919 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), &floatData[0]);
2920 drawQuad(program1, essl3_shaders::PositionAttrib(), 0.5f);
2921 checkResults(GLColor::blue, GLColor::blue, GLColor::blue, GLColor::blue);
2922
2923 setArrayValues(floatData, 0, arraySize2, 16, 0, 4, 4, 0.0f, 1.0f, 0.0f, 1.0f);
2924 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount2 * sizeof(GLfloat), &floatData[0]);
2925 drawQuad(program2, essl3_shaders::PositionAttrib(), 0.5f);
2926 checkResults(GLColor::green, GLColor::green, GLColor::green, GLColor::green);
2927
2928 setArrayValues(floatData, arraySize2, arraySize2 + arraySize1 / 2, 16, 0, 4, 4, 0.0f, 1.0f,
2929 0.0f, 1.0f);
2930 glBufferSubData(GL_UNIFORM_BUFFER, floatCount2 * sizeof(GLfloat),
2931 (floatCount1 / 2 - floatCount2) * sizeof(GLfloat), &floatData[0]);
2932 drawQuad(program1, essl3_shaders::PositionAttrib(), 0.5f);
2933 checkResults(GLColor::green, GLColor::green, GLColor::blue, GLColor::blue);
2934 }
2935
2936 // Test two uniform blocks share the same uniform buffer. On D3D backend, a uniform
2937 // block with a large array member will be translated to StructuredBuffer, and the
2938 // other uniform block will be translated to cbuffer, this case verifies that update
2939 // buffer data correctly.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,SharedSameBufferWithOtherOne)2940 TEST_P(UniformBlockWithOneLargeArrayMemberTest, SharedSameBufferWithOtherOne)
2941 {
2942 ANGLE_SKIP_TEST_IF(IsIntel() && IsMac() && IsOpenGL());
2943
2944 std::ostringstream stream;
2945 generateArraySizeAndDivisorsDeclaration(stream, false, true, false);
2946 const std::string &kFS =
2947 "#version 300 es\n"
2948 "precision highp float;\n" +
2949 stream.str() +
2950 "out vec4 my_FragColor;\n"
2951 "struct S { mat4 color;};\n"
2952 "layout(std140) uniform buffer { S s[arraySize]; };\n"
2953 "layout(std140) uniform buffer1 { vec4 factor; };\n"
2954 "void main()\n"
2955 "{\n"
2956 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
2957 " uint index = coord.x + coord.y * 128u;\n"
2958 " uint index_x = index / divisor1;\n"
2959 " uint index_y = (index % divisor1) / divisor2;\n"
2960 " my_FragColor = s[index_x].color[index_y] + factor;\n"
2961 "}\n";
2962
2963 GLint blockSize;
2964 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
2965 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
2966 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
2967 GLint uniformBufferIndex1 = glGetUniformBlockIndex(program, "buffer1");
2968 GLint alignment;
2969 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
2970 while (alignment >= 0 && alignment < 16)
2971 {
2972 alignment += alignment;
2973 }
2974
2975 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
2976 glBufferData(GL_UNIFORM_BUFFER, alignment + blockSize, nullptr, GL_STATIC_DRAW);
2977
2978 const GLuint arraySize = getArraySize();
2979 const GLuint floatCount = arraySize * kVectorPerMat * kFloatPerVector;
2980 std::vector<GLfloat> floatData(floatCount, 0.0f);
2981 std::vector<GLfloat> floatData1(4, 0.0f);
2982
2983 setArrayValues(floatData, 0, arraySize, 16, 0, 4, 4, 0.0f, 0.0f, 0.5f, 0.5f);
2984 setArrayValues(floatData1, 0, 1, 4, 0, 1, 4, 1.0f, 0.0f, 0.5f, 0.5f);
2985 glBindBufferRange(GL_UNIFORM_BUFFER, 0, mUniformBuffer, 0, 4 * sizeof(float));
2986 glUniformBlockBinding(program, uniformBufferIndex1, 0);
2987 glBindBufferRange(GL_UNIFORM_BUFFER, 1, mUniformBuffer, alignment, floatCount * sizeof(float));
2988 glUniformBlockBinding(program, uniformBufferIndex, 1);
2989
2990 glBufferSubData(GL_UNIFORM_BUFFER, alignment, floatCount * sizeof(GLfloat), floatData.data());
2991 glBufferSubData(GL_UNIFORM_BUFFER, 0, 4 * sizeof(GLfloat), floatData1.data());
2992 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
2993 checkResults(GLColor::magenta, GLColor::magenta, GLColor::magenta, GLColor::magenta);
2994
2995 setArrayValues(floatData, 0, arraySize, 16, 0, 4, 4, 0.0f, 0.5f, 0.0f, 0.5f);
2996 setArrayValues(floatData1, 0, 1, 4, 0, 1, 4, 0.0f, 0.5f, 0.0f, 0.5f);
2997 glBufferSubData(GL_UNIFORM_BUFFER, alignment, floatCount * sizeof(GLfloat), floatData.data());
2998 glBufferSubData(GL_UNIFORM_BUFFER, 0, 4 * sizeof(GLfloat), floatData1.data());
2999 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3000 checkResults(GLColor::green, GLColor::green, GLColor::green, GLColor::green);
3001 }
3002
3003 // Test indexing accesses uniform block with a large matrix array member correctly.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsMatrixAndIndexAccess)3004 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsMatrixAndIndexAccess)
3005 {
3006 const char *kFS = R"(#version 300 es
3007 precision mediump float;
3008
3009 uniform uint index;
3010
3011 struct S { uvec4 idx; };
3012
3013 layout(std140) uniform idxbuf { S idxArray[2]; };
3014
3015 layout(std140) uniform buffer1 { mat4 s1[128]; };
3016 layout(std140) uniform buffer2 { mat4 s2[128]; } buf2[2];
3017
3018 out vec4 fragColor;
3019 void main()
3020 {
3021 fragColor = s1[1][0] + s1[index][1] + s1[idxArray[0].idx.x][idxArray[1].idx.z]
3022 + buf2[0].s2[1][0] + buf2[1].s2[index][1] + buf2[0].s2[idxArray[0].idx.y][idxArray[1].idx.z]
3023 + vec4(buf2[1].s2[index][1][index], s1[1][0][2], s1[idxArray[0].idx.x][idxArray[1].idx.z][2],
3024 buf2[0].s2[idxArray[0].idx.y][idxArray[1].idx.z][3]);
3025 })";
3026
3027 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
3028 ASSERT_GL_NO_ERROR();
3029 }
3030
3031 // Test uniform block whose member is matrix type.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsMatrix)3032 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsMatrix)
3033 {
3034 std::ostringstream stream;
3035 generateArraySizeAndDivisorsDeclaration(stream, false, true, false);
3036 const std::string &kFS =
3037 "#version 300 es\n"
3038 "precision highp float;\n" +
3039 stream.str() +
3040 "out vec4 my_FragColor;\n"
3041 "layout(std140) uniform buffer { mat4 s[arraySize]; };\n"
3042 "void main()\n"
3043 "{\n"
3044 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
3045 " uint index = coord.x + coord.y * 128u;\n"
3046 " uint index_x = index / divisor1;\n"
3047 " uint index_y = (index % divisor1) / divisor2;\n"
3048 " my_FragColor = s[index_x][index_y];\n"
3049 "}\n";
3050
3051 GLint blockSize;
3052 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
3053 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
3054 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
3055
3056 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
3057 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
3058
3059 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
3060 glUniformBlockBinding(program, uniformBufferIndex, 0);
3061
3062 const GLuint arraySize = getArraySize();
3063 const GLuint floatCount = arraySize * kVectorPerMat * kFloatPerVector;
3064 std::vector<GLfloat> floatData(floatCount, 0.0f);
3065
3066 setArrayValues(floatData, 0, arraySize, 16, 0, 4, 4, 0.0f, 0.0f, 1.0f, 1.0f);
3067 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3068 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3069 checkResults(GLColor::blue, GLColor::blue, GLColor::blue, GLColor::blue);
3070
3071 setArrayValues(floatData, 0, arraySize, 16, 0, 4, 4, 0.0f, 1.0f, 0.0f, 1.0f);
3072 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3073 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3074 checkResults(GLColor::green, GLColor::green, GLColor::green, GLColor::green);
3075
3076 setArrayValues(floatData, arraySize / 4, arraySize / 2, 16, 0, 4, 4, 1.0f, 0.0f, 0.0f, 1.0f);
3077 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3078 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3079 checkResults(GLColor::green, GLColor::red, GLColor::green, GLColor::green);
3080 }
3081
3082 // Test instanced uniform block whose member is matrix type.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsMatrixAndInstanced)3083 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsMatrixAndInstanced)
3084 {
3085 std::ostringstream stream;
3086 generateArraySizeAndDivisorsDeclaration(stream, false, true, false);
3087 const std::string &kFS =
3088 "#version 300 es\n"
3089 "precision highp float;\n" +
3090 stream.str() +
3091 "out vec4 my_FragColor;\n"
3092 "layout(std140) uniform buffer { mat4 s[arraySize]; } instance[2];\n"
3093 "void main()\n"
3094 "{\n"
3095 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
3096 " uint index = coord.x + coord.y * 128u;\n"
3097 " uint index_x = index / divisor1;\n"
3098 " uint index_y = (index % divisor1) / divisor2;\n"
3099 " my_FragColor = instance[0].s[index_x][index_y] + "
3100 "instance[1].s[index_x][index_y];\n"
3101 "}\n";
3102
3103 GLint blockSize0, blockSize1;
3104 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
3105 GLint uniformBufferIndex0 = glGetUniformBlockIndex(program, "buffer[0]");
3106 GLint uniformBufferIndex1 = glGetUniformBlockIndex(program, "buffer[1]");
3107 glGetActiveUniformBlockiv(program, uniformBufferIndex0, GL_UNIFORM_BLOCK_DATA_SIZE,
3108 &blockSize0);
3109 glGetActiveUniformBlockiv(program, uniformBufferIndex1, GL_UNIFORM_BLOCK_DATA_SIZE,
3110 &blockSize1);
3111
3112 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
3113 glBufferData(GL_UNIFORM_BUFFER, blockSize0, nullptr, GL_STATIC_DRAW);
3114
3115 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
3116 glUniformBlockBinding(program, uniformBufferIndex0, 0);
3117
3118 const GLuint arraySize = getArraySize();
3119 const GLuint floatCount = arraySize * kVectorPerMat * kFloatPerVector;
3120 std::vector<GLfloat> floatData0(floatCount, 0.0f);
3121 std::vector<GLfloat> floatData1(floatCount, 0.0f);
3122
3123 setArrayValues(floatData0, 0, arraySize, 16, 0, 4, 4, 0.0f, 0.0f, 1.0f, 1.0f);
3124 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData0.data());
3125
3126 GLBuffer uniformBuffer1;
3127 glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer1);
3128 glBufferData(GL_UNIFORM_BUFFER, blockSize1, nullptr, GL_STATIC_DRAW);
3129
3130 glBindBufferBase(GL_UNIFORM_BUFFER, 1, uniformBuffer1);
3131 glUniformBlockBinding(program, uniformBufferIndex0, 1);
3132
3133 setArrayValues(floatData1, 0, arraySize, 16, 0, 4, 4, 0.0f, 1.0f, 0.0f, 0.0f);
3134 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData1.data());
3135 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3136 checkResults(GLColor::cyan, GLColor::cyan, GLColor::cyan, GLColor::cyan);
3137
3138 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
3139 setArrayValues(floatData0, 0, arraySize, 16, 0, 4, 4, 1.0f, 0.0f, 0.0f, 1.0f);
3140 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData0.data());
3141 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3142 checkResults(GLColor::yellow, GLColor::yellow, GLColor::yellow, GLColor::yellow);
3143
3144 glBindBuffer(GL_UNIFORM_BUFFER, uniformBuffer1);
3145 setArrayValues(floatData1, arraySize / 4, arraySize / 2, 16, 0, 4, 4, 0.0f, 0.0f, 1.0f, 0.0f);
3146 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData1.data());
3147 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3148 checkResults(GLColor::yellow, GLColor::magenta, GLColor::yellow, GLColor::yellow);
3149 }
3150
3151 // Test uniform block with row major qualifier whose member is matrix type.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsMatrixAndRowMajorQualifier)3152 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsMatrixAndRowMajorQualifier)
3153 {
3154 // http://anglebug.com/42262481 , http://anglebug.com/40096480
3155 ANGLE_SKIP_TEST_IF((IsMac() && IsOpenGL()) || IsAndroid() || (IsAMD() && IsOpenGL()) ||
3156 (IsLinux() && IsIntel() && IsOpenGL()));
3157
3158 std::ostringstream stream;
3159 generateArraySizeAndDivisorsDeclaration(stream, false, true, false);
3160 const std::string &kFS =
3161 "#version 300 es\n"
3162 "precision highp float;\n" +
3163 stream.str() +
3164 "out vec4 my_FragColor;\n"
3165 "layout(std140, row_major) uniform buffer { mat4 s[arraySize]; };\n"
3166 "void main()\n"
3167 "{\n"
3168 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
3169 " uint index = coord.x + coord.y * 128u;\n"
3170 " uint index_x = index / divisor1;\n"
3171 " uint index_y = (index % divisor1) / divisor2;\n"
3172 " my_FragColor = s[index_x][index_y];\n"
3173 "}\n";
3174
3175 GLint blockSize;
3176 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
3177 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
3178 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
3179
3180 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
3181 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
3182
3183 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
3184 glUniformBlockBinding(program, uniformBufferIndex, 0);
3185
3186 const GLuint arraySize = getArraySize();
3187 const GLuint floatCount = arraySize * kVectorPerMat * kFloatPerVector;
3188 std::vector<GLfloat> floatData(floatCount, 0.0f);
3189
3190 setArrayValues(floatData, 0, arraySize, 16, 0, 2, 4, 0.0f, 0.0f, 0.0f, 0.0f, 8, 2, 4, 1.0f,
3191 1.0f, 1.0f, 1.0f);
3192 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3193 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3194 checkResults(GLColor::blue, GLColor::blue, GLColor::blue, GLColor::blue);
3195
3196 setArrayValues(floatData, 0, arraySize, 16, 4, 1, 4, 1.0f, 1.0f, 1.0f, 1.0f, 8, 1, 4, 0.0f,
3197 0.0f, 0.0f, 0.0f);
3198 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3199 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3200 checkResults(GLColor::green, GLColor::green, GLColor::green, GLColor::green);
3201
3202 setArrayValues(floatData, arraySize / 4, arraySize / 2, 16, 0, 1, 4, 1.0f, 1.0f, 1.0f, 1.0f, 4,
3203 1, 4, 0.0f, 0.0f, 0.0f, 0.0f);
3204 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3205 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3206 checkResults(GLColor::green, GLColor::red, GLColor::green, GLColor::green);
3207 }
3208
3209 // Test uniform block whose member is vec4 type.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsVec4)3210 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsVec4)
3211 {
3212 std::ostringstream stream;
3213 generateArraySizeAndDivisorsDeclaration(stream, false, false, false);
3214 const std::string &kFS =
3215 "#version 300 es\n"
3216 "precision highp float;\n" +
3217 stream.str() +
3218 "out vec4 my_FragColor;\n"
3219 "layout(std140) uniform buffer { vec4 s[arraySize]; };\n"
3220 "void main()\n"
3221 "{\n"
3222 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
3223 " uint index = (coord.x + coord.y * 128u) / divisor;\n"
3224 " my_FragColor = s[index];\n"
3225 "}\n";
3226
3227 GLint blockSize;
3228 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
3229 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
3230 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
3231
3232 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
3233 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
3234
3235 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
3236 glUniformBlockBinding(program, uniformBufferIndex, 0);
3237
3238 const GLuint arraySize = getArraySize();
3239 const GLuint floatCount = arraySize * kFloatPerVector;
3240 std::vector<GLfloat> floatData(floatCount, 0.0f);
3241
3242 setArrayValues(floatData, 0, arraySize, 4, 0, 1, 4, 1.0f, 0.0f, 1.0f, 1.0f);
3243 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3244 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3245 checkResults(GLColor::magenta, GLColor::magenta, GLColor::magenta, GLColor::magenta);
3246
3247 setArrayValues(floatData, 0, arraySize, 4, 0, 1, 4, 1.0f, 1.0f, 0.0f, 1.0f);
3248 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3249 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3250 checkResults(GLColor::yellow, GLColor::yellow, GLColor::yellow, GLColor::yellow);
3251 }
3252
3253 // Test uniform block whose member is vec3 type.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsVec3)3254 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsVec3)
3255 {
3256 std::ostringstream stream;
3257 generateArraySizeAndDivisorsDeclaration(stream, false, false, false);
3258 const std::string &kFS =
3259 "#version 300 es\n"
3260 "precision highp float;\n" +
3261 stream.str() +
3262 "out vec4 my_FragColor;\n"
3263 "layout(std140) uniform buffer { vec3 s[arraySize]; };\n"
3264 "void main()\n"
3265 "{\n"
3266 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
3267 " uint index = (coord.x + coord.y * 128u) / divisor;\n"
3268 " my_FragColor = vec4(s[index], 1.0);\n"
3269 "}\n";
3270
3271 GLint blockSize;
3272 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
3273 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
3274 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
3275
3276 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
3277 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
3278
3279 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
3280 glUniformBlockBinding(program, uniformBufferIndex, 0);
3281
3282 const GLuint arraySize = getArraySize();
3283 const GLuint floatCount = arraySize * kFloatPerVector;
3284 std::vector<GLfloat> floatData(floatCount, 0.0f);
3285
3286 setArrayValues(floatData, 0, arraySize, 4, 0, 1, 3, 0.0f, 0.0f, 1.0f, 0.0f);
3287 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3288 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3289 checkResults(GLColor::blue, GLColor::blue, GLColor::blue, GLColor::blue);
3290
3291 setArrayValues(floatData, 0, arraySize, 4, 0, 1, 3, 0.0f, 1.0f, 0.0f, 0.0f);
3292 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3293 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3294 checkResults(GLColor::green, GLColor::green, GLColor::green, GLColor::green);
3295
3296 setArrayValues(floatData, arraySize / 4, arraySize / 2, 4, 0, 1, 3, 1.0f, 0.0f, 0.0f, 0.0f);
3297 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3298 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3299 checkResults(GLColor::green, GLColor::red, GLColor::green, GLColor::green);
3300 }
3301
3302 // Test uniform block whose member is vec2 type.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsVec2)3303 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsVec2)
3304 {
3305 std::ostringstream stream;
3306 generateArraySizeAndDivisorsDeclaration(stream, false, false, false);
3307 const std::string &kFS =
3308 "#version 300 es\n"
3309 "precision highp float;\n" +
3310 stream.str() +
3311 "out vec4 my_FragColor;\n"
3312 "layout(std140) uniform buffer { vec2 s[arraySize]; };\n"
3313 "void main()\n"
3314 "{\n"
3315 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
3316 " uint index = (coord.x + coord.y * 128u) / divisor;\n"
3317 " my_FragColor = vec4(s[index], s[index].x, 1.0);\n"
3318 "}\n";
3319
3320 GLint blockSize;
3321 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
3322 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
3323 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
3324
3325 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
3326 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
3327
3328 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
3329 glUniformBlockBinding(program, uniformBufferIndex, 0);
3330
3331 const GLuint arraySize = getArraySize();
3332 const GLuint floatCount = arraySize * kFloatPerVector;
3333 std::vector<GLfloat> floatData(floatCount, 0.0f);
3334
3335 setArrayValues(floatData, 0, arraySize, 4, 0, 1, 2, 1.0f, 0.0f, 0.0f, 0.0f);
3336 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3337 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3338 checkResults(GLColor::magenta, GLColor::magenta, GLColor::magenta, GLColor::magenta);
3339
3340 setArrayValues(floatData, 0, arraySize, 4, 0, 1, 2, 0.0f, 1.0f, 0.0f, 0.0f);
3341 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3342 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3343 checkResults(GLColor::green, GLColor::green, GLColor::green, GLColor::green);
3344
3345 setArrayValues(floatData, arraySize / 4, arraySize / 2, 4, 0, 1, 2, 1.0f, 0.0f, 0.0f, 0.0f);
3346 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3347 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3348 checkResults(GLColor::green, GLColor::magenta, GLColor::green, GLColor::green);
3349 }
3350
3351 // Test uniform block whose member is float type.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsFloat)3352 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsFloat)
3353 {
3354 std::ostringstream stream;
3355 generateArraySizeAndDivisorsDeclaration(stream, false, false, false);
3356 const std::string &kFS =
3357 "#version 300 es\n"
3358 "precision highp float;\n" +
3359 stream.str() +
3360 "out vec4 my_FragColor;\n"
3361 "layout(std140) uniform buffer { float s[arraySize]; };\n"
3362 "void main()\n"
3363 "{\n"
3364 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
3365 " uint index = (coord.x + coord.y * 128u) / divisor;\n"
3366 " my_FragColor = vec4(s[index], 0.0, 0.0, 1.0);\n"
3367 "}\n";
3368
3369 GLint blockSize;
3370 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
3371 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
3372 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
3373
3374 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
3375 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
3376
3377 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
3378 glUniformBlockBinding(program, uniformBufferIndex, 0);
3379
3380 // The base alignment and array stride are rounded up to the base alignment of a vec4.
3381 const GLuint arraySize = getArraySize();
3382 const GLuint floatCount = arraySize * kFloatPerVector;
3383 std::vector<GLfloat> floatData(floatCount, 0.0f);
3384
3385 setArrayValues(floatData, 0, arraySize, 4, 0, 1, 1, 1.0f, 0.0f, 0.0f, 0.0f);
3386 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3387 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3388 checkResults(GLColor::red, GLColor::red, GLColor::red, GLColor::red);
3389
3390 setArrayValues(floatData, arraySize / 4, arraySize / 2, 4, 0, 1, 1, 0.0f, 0.0f, 0.0f, 0.0f);
3391 glBufferSubData(GL_UNIFORM_BUFFER, 0, floatCount * sizeof(GLfloat), floatData.data());
3392 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3393 checkResults(GLColor::red, GLColor::black, GLColor::red, GLColor::red);
3394 }
3395
3396 // Test uniform block whose member is structure type, which contains a float member and a mat4
3397 // member.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsMixStructFloatAndMat4)3398 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsMixStructFloatAndMat4)
3399 {
3400 std::ostringstream stream;
3401 generateArraySizeAndDivisorsDeclaration(stream, false, true, false);
3402 const std::string &kFS =
3403 "#version 300 es\n"
3404 "precision highp float;\n" +
3405 stream.str() +
3406 "out vec4 my_FragColor;\n"
3407 "struct S { float factor; mat4 color; };\n"
3408 "layout(std140) uniform buffer { S s[arraySize]; };\n"
3409 "void main()\n"
3410 "{\n"
3411 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
3412 " uint index = coord.x + coord.y * 128u;\n"
3413 " uint index_x = index / divisor1;\n"
3414 " uint index_y = (index % divisor1) / divisor2;\n"
3415 " my_FragColor = s[index_x].factor * s[index_x].color[index_y];\n"
3416 "}\n";
3417
3418 GLint blockSize;
3419 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
3420 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
3421 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
3422
3423 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
3424 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
3425
3426 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
3427 glUniformBlockBinding(program, uniformBufferIndex, 0);
3428
3429 // The member s is an array of S structures, each element of s should be rounded up
3430 // to the base alignment of a vec4 according to std140 storage layout rules.
3431 const GLuint arraySize = getArraySize();
3432 const GLuint floatCount = arraySize * (kVectorPerMat * kFloatPerVector + kFloatPerVector);
3433 std::vector<GLfloat> floatData(floatCount, 0.0f);
3434 const size_t strideofFloatCount = kVectorPerMat * kFloatPerVector + kFloatPerVector;
3435
3436 setArrayValues(floatData, 0, arraySize, strideofFloatCount, 0, 1, 1, 2.0f, 0.0f, 0.0f, 0.0f, 4,
3437 4, 4, 0.0f, 0.0f, 0.5f, 0.5f);
3438 glBufferSubData(GL_UNIFORM_BUFFER, 0,
3439 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
3440 floatData.data());
3441 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3442 checkResults(GLColor::blue, GLColor::blue, GLColor::blue, GLColor::blue);
3443
3444 setArrayValues(floatData, 0, arraySize, strideofFloatCount, 0, 1, 1, 2.0f, 0.0f, 0.0f, 0.0f, 4,
3445 4, 4, 0.0f, 0.5f, 0.0f, 0.5f);
3446 glBufferSubData(GL_UNIFORM_BUFFER, 0,
3447 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
3448 floatData.data());
3449 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3450 checkResults(GLColor::green, GLColor::green, GLColor::green, GLColor::green);
3451
3452 setArrayValues(floatData, arraySize / 4, arraySize / 2, strideofFloatCount, 0, 1, 1, 2.0f, 0.0f,
3453 0.0f, 0.0f, 4, 4, 4, 0.5f, 0.0f, 0.0f, 0.5f);
3454 glBufferSubData(GL_UNIFORM_BUFFER, 0,
3455 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
3456 floatData.data());
3457 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3458 checkResults(GLColor::green, GLColor::red, GLColor::green, GLColor::green);
3459 }
3460
3461 // Test uniform block whose member is structure type, which contains a float member and a vec4
3462 // member.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberTypeIsMixStructFloatAndVec4)3463 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberTypeIsMixStructFloatAndVec4)
3464 {
3465 std::ostringstream stream;
3466 generateArraySizeAndDivisorsDeclaration(stream, false, false, false);
3467 const std::string &kFS =
3468 "#version 300 es\n"
3469 "precision highp float;\n" +
3470 stream.str() +
3471 "out vec4 my_FragColor;\n"
3472 "struct S { float color1; vec4 color2; };\n"
3473 "layout(std140) uniform buffer { S s[arraySize]; };\n"
3474 "void main()\n"
3475 "{\n"
3476 " uvec2 coord = uvec2(floor(gl_FragCoord.xy));\n"
3477 " uint index = (coord.x + coord.y * 128u) / divisor;\n"
3478 " my_FragColor = vec4(s[index].color1, s[index].color2.xyz);\n"
3479 "}\n";
3480
3481 GLint blockSize;
3482 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS.c_str());
3483 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
3484 glGetActiveUniformBlockiv(program, uniformBufferIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
3485
3486 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
3487 glBufferData(GL_UNIFORM_BUFFER, blockSize, nullptr, GL_STATIC_DRAW);
3488
3489 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
3490 glUniformBlockBinding(program, uniformBufferIndex, 0);
3491
3492 const GLuint arraySize = getArraySize();
3493 const GLuint floatCount = arraySize * 2 * kFloatPerVector;
3494 std::vector<GLfloat> floatData(floatCount, 0.0f);
3495 const size_t strideofFloatCount = 2 * kFloatPerVector;
3496
3497 setArrayValues(floatData, 0, arraySize, strideofFloatCount, 0, 1, 1, 1.0f, 0.0f, 0.0f, 0.0f, 4,
3498 1, 4, 1.0f, 1.0f, 1.0f, 0.0f);
3499 glBufferSubData(GL_UNIFORM_BUFFER, 0,
3500 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
3501 floatData.data());
3502 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3503 checkResults(GLColor::white, GLColor::white, GLColor::white, GLColor::white);
3504
3505 setArrayValues(floatData, 0, arraySize, strideofFloatCount, 0, 1, 1, 1.0f, 0.0f, 0.0f, 0.0f, 4,
3506 1, 4, 0.0f, 0.0f, 1.0f, 0.0f);
3507 glBufferSubData(GL_UNIFORM_BUFFER, 0,
3508 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
3509 floatData.data());
3510 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3511 checkResults(GLColor::red, GLColor::red, GLColor::red, GLColor::red);
3512
3513 setArrayValues(floatData, arraySize / 4, arraySize / 2, strideofFloatCount, 0, 1, 1, 0.0f, 0.0f,
3514 0.0f, 0.0f, 4, 1, 4, 0.0f, 1.0f, 1.0f, 0.0f);
3515 glBufferSubData(GL_UNIFORM_BUFFER, 0,
3516 std::min(static_cast<size_t>(blockSize), floatCount * sizeof(GLfloat)),
3517 floatData.data());
3518 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
3519 checkResults(GLColor::red, GLColor::blue, GLColor::red, GLColor::red);
3520 }
3521
3522 // Test to transfer a uniform block large array member as an actual parameter to a function.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberAsActualParameter)3523 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberAsActualParameter)
3524 {
3525 ANGLE_SKIP_TEST_IF(IsAdreno());
3526
3527 constexpr char kVS[] = R"(#version 300 es
3528 layout(location=0) in vec3 a_position;
3529
3530 layout(std140) uniform UBO1{
3531 mat4x4 buf1[90];
3532 } instance;
3533
3534 layout(std140) uniform UBO2{
3535 mat4x4 buf2[90];
3536 };
3537
3538 vec4 test(mat4x4[90] para1, mat4x4[90] para2, vec3 pos){
3539 return para1[0] * para2[0] * vec4(pos, 1.0);
3540 }
3541
3542 void main(void){
3543 gl_Position = test(instance.buf1, buf2, a_position);
3544 })";
3545
3546 constexpr char kFS[] = R"(#version 300 es
3547 precision mediump float;
3548
3549 uniform vec3 u_color;
3550 out vec4 oFragColor;
3551
3552 void main(void){
3553 oFragColor = vec4( u_color, 1.0);
3554 })";
3555
3556 ANGLE_GL_PROGRAM(program, kVS, kFS);
3557 EXPECT_GL_NO_ERROR();
3558 }
3559
3560 // Test array operators to operate on uniform block large array member.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,MemberArrayOperations)3561 TEST_P(UniformBlockWithOneLargeArrayMemberTest, MemberArrayOperations)
3562 {
3563 ANGLE_SKIP_TEST_IF(IsOpenGL() || IsOpenGLES());
3564
3565 constexpr char kVS[] = R"(#version 300 es
3566 layout(location=0) in vec3 a_position;
3567
3568 layout(std140) uniform UBO1{
3569 mat4x4 buf1[90];
3570 };
3571
3572 layout(std140) uniform UBO2{
3573 mat4x4 buf2[90];
3574 };
3575
3576 layout(std140) uniform UBO3{
3577 mat4x4 buf[90];
3578 } instance;
3579
3580 vec4 test1( mat4x4[90] para, vec3 pos ){
3581 return para[ 0 ] * vec4( pos, 1.0 );
3582 }
3583
3584 mat4x4[90] test2()
3585 {
3586 return instance.buf;
3587 }
3588
3589 void main(void){
3590 if (buf1 == buf2)
3591 {
3592 mat4x4 temp1[90] = buf1;
3593 gl_Position = test1(temp1, a_position);
3594 }
3595 else
3596 {
3597 mat4x4 temp2[90] = test2();
3598 gl_Position = test1(temp2, a_position);
3599 }
3600 })";
3601
3602 constexpr char kFS[] = R"(#version 300 es
3603 precision mediump float;
3604
3605 uniform vec3 u_color;
3606 out vec4 oFragColor;
3607
3608 void main(void){
3609 oFragColor = vec4( u_color, 1.0);
3610 })";
3611
3612 ANGLE_GL_PROGRAM(program, kVS, kFS);
3613 EXPECT_GL_NO_ERROR();
3614 }
3615
3616 // Test to throw a warning if a uniform block with a large array member
3617 // fails to hit the optimization on D3D backend.
TEST_P(UniformBlockWithOneLargeArrayMemberTest,ThrowPerfWarningInD3D)3618 TEST_P(UniformBlockWithOneLargeArrayMemberTest, ThrowPerfWarningInD3D)
3619 {
3620 constexpr char kFS[] = R"(#version 300 es
3621 precision highp float;
3622
3623 struct S1 {
3624 vec2 a[2];
3625 };
3626
3627 struct S2 {
3628 mat2x4 b;
3629 };
3630
3631 layout(std140, row_major) uniform UBO1{
3632 mat3x2 buf1[128];
3633 };
3634
3635 layout(std140, row_major) uniform UBO2{
3636 mat4x3 buf2[128];
3637 } instance1;
3638
3639 layout(std140, row_major) uniform UBO3{
3640 S1 buf3[128];
3641 };
3642
3643 layout(std140, row_major) uniform UBO4{
3644 S2 buf4[128];
3645 } instance2[2];
3646
3647 out vec4 my_FragColor;
3648
3649 void main(void){
3650 uvec2 coord = uvec2(floor(gl_FragCoord.xy));
3651 uint x = coord.x % 64u;
3652 uint y = coord.y;
3653 my_FragColor = vec4(buf1[y]*instance1.buf2[y]*instance2[0].buf4[y].b*buf3[y].a[x], 0.0f, 1.0);
3654
3655 })";
3656
3657 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
3658 EXPECT_GL_NO_ERROR();
3659 }
3660
3661 // Tests rendering with a bound, unreferenced UBO that has no data. Covers a paticular back-end bug.
TEST_P(UniformBufferTest,EmptyUnusedUniformBuffer)3662 TEST_P(UniformBufferTest, EmptyUnusedUniformBuffer)
3663 {
3664 constexpr GLuint kBasicUBOIndex = 0;
3665 constexpr GLuint kEmptyUBOIndex = 1;
3666
3667 // Create two UBOs. One is empty and the other is used.
3668 constexpr GLfloat basicUBOData[4] = {1.0, 2.0, 3.0, 4.0};
3669 GLBuffer basicUBO;
3670 glBindBuffer(GL_UNIFORM_BUFFER, basicUBO);
3671 glBufferData(GL_UNIFORM_BUFFER, sizeof(basicUBOData), basicUBOData, GL_STATIC_READ);
3672 glBindBufferBase(GL_UNIFORM_BUFFER, kBasicUBOIndex, basicUBO);
3673
3674 GLBuffer emptyUBO;
3675 glBindBufferBase(GL_UNIFORM_BUFFER, kEmptyUBOIndex, emptyUBO);
3676
3677 // Create a simple UBO program.
3678 constexpr char kFS[] = R"(#version 300 es
3679 precision mediump float;
3680 uniform basicBlock {
3681 vec4 basicVec4;
3682 };
3683
3684 out vec4 outColor;
3685
3686 void main() {
3687 if (basicVec4 == vec4(1, 2, 3, 4)) {
3688 outColor = vec4(0, 1, 0, 1);
3689 } else {
3690 outColor = vec4(1, 0, 0, 1);
3691 }
3692 })";
3693
3694 // Draw and check result. Should not crash.
3695 ANGLE_GL_PROGRAM(uboProgram, essl3_shaders::vs::Simple(), kFS);
3696 drawQuad(uboProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f);
3697 EXPECT_GL_NO_ERROR();
3698 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3699 }
3700
3701 // Calling BufferData and use it in a loop to force descriptorSet creation and destroy.
TEST_P(UniformBufferTest,BufferDataInLoop)3702 TEST_P(UniformBufferTest, BufferDataInLoop)
3703 {
3704 glClear(GL_COLOR_BUFFER_BIT);
3705
3706 // Use large buffer size to get around suballocation, so that we will gets a new buffer with
3707 // bufferData call.
3708 static constexpr size_t kBufferSize = 4 * 1024 * 1024;
3709 std::vector<float> floatData;
3710 floatData.resize(kBufferSize / (sizeof(float)), 0.0f);
3711 floatData[0] = 0.5f;
3712 floatData[1] = 0.75f;
3713 floatData[2] = 0.25f;
3714 floatData[3] = 1.0f;
3715
3716 GLTexture textures[2];
3717 GLFramebuffer fbos[2];
3718 for (int i = 0; i < 2; i++)
3719 {
3720 glBindTexture(GL_TEXTURE_2D, textures[i]);
3721 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256);
3722
3723 glBindFramebuffer(GL_FRAMEBUFFER, fbos[i]);
3724 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[i], 0);
3725 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
3726 }
3727
3728 for (int loop = 0; loop < 10; loop++)
3729 {
3730 int i = loop & 0x1;
3731 // Switch FBO to get around deferred flush
3732 glBindFramebuffer(GL_FRAMEBUFFER, fbos[i]);
3733 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
3734 glBufferData(GL_UNIFORM_BUFFER, kBufferSize, floatData.data(), GL_STATIC_DRAW);
3735
3736 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
3737 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
3738 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
3739 glFlush();
3740 }
3741 ASSERT_GL_NO_ERROR();
3742 EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
3743 }
3744
3745 class UniformBufferMemoryTest : public UniformBufferTest
3746 {
3747 protected:
getPerfCounters()3748 angle::VulkanPerfCounters getPerfCounters()
3749 {
3750 if (mIndexMap.empty())
3751 {
3752 mIndexMap = BuildCounterNameToIndexMap();
3753 }
3754
3755 return GetPerfCounters(mIndexMap);
3756 }
3757
3758 CounterNameToIndexMap mIndexMap;
3759 };
3760
3761 // Calling BufferData and drawing with it in a loop without glFlush() should still work. Driver is
3762 // supposedly to issue flush if needed.
TEST_P(UniformBufferMemoryTest,BufferDataInLoopManyTimes)3763 TEST_P(UniformBufferMemoryTest, BufferDataInLoopManyTimes)
3764 {
3765 GLPerfMonitor monitor;
3766 glBeginPerfMonitorAMD(monitor);
3767
3768 // Run this test for Vulkan only.
3769 ANGLE_SKIP_TEST_IF(!IsVulkan());
3770 uint64_t expectedSubmitCalls = getPerfCounters().commandQueueSubmitCallsTotal + 1;
3771
3772 glClear(GL_COLOR_BUFFER_BIT);
3773 constexpr size_t kBufferSize = 64 * 1024 * 1024;
3774 std::vector<float> floatData;
3775 floatData.resize(kBufferSize / (sizeof(float)), 0.0f);
3776 floatData[0] = 0.5f;
3777 floatData[1] = 0.75f;
3778 floatData[2] = 0.25f;
3779 floatData[3] = 1.0f;
3780
3781 GLTexture texture;
3782 GLFramebuffer fbo;
3783
3784 glBindTexture(GL_TEXTURE_2D, texture);
3785 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 256);
3786
3787 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3788 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
3789 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
3790
3791 constexpr uint32_t kIterationCount = 4096;
3792 for (uint32_t loop = 0; loop < kIterationCount; loop++)
3793 {
3794 glBindBuffer(GL_UNIFORM_BUFFER, mUniformBuffer);
3795 glBufferData(GL_UNIFORM_BUFFER, kBufferSize, nullptr, GL_STATIC_DRAW);
3796 glBufferSubData(GL_UNIFORM_BUFFER, 0, kBufferSize, floatData.data());
3797
3798 glBindBufferBase(GL_UNIFORM_BUFFER, 0, mUniformBuffer);
3799 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
3800 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
3801
3802 if (getPerfCounters().commandQueueSubmitCallsTotal == expectedSubmitCalls)
3803 {
3804 break;
3805 }
3806 }
3807 glEndPerfMonitorAMD(monitor);
3808
3809 EXPECT_EQ(getPerfCounters().commandQueueSubmitCallsTotal, expectedSubmitCalls);
3810 ASSERT_GL_NO_ERROR();
3811 EXPECT_PIXEL_NEAR(0, 0, 128, 191, 64, 255, 1);
3812 }
3813
3814 class WebGL2UniformBufferTest : public UniformBufferTest
3815 {
3816 protected:
WebGL2UniformBufferTest()3817 WebGL2UniformBufferTest() { setWebGLCompatibilityEnabled(true); }
3818 };
3819
3820 // Test that ANGLE handles used but unbound UBO. Assumes we are running on ANGLE and produce
3821 // optional but not mandatory errors.
TEST_P(WebGL2UniformBufferTest,ANGLEUnboundUniformBuffer)3822 TEST_P(WebGL2UniformBufferTest, ANGLEUnboundUniformBuffer)
3823 {
3824 glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
3825 glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0);
3826 EXPECT_GL_NO_ERROR();
3827
3828 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
3829 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
3830 }
3831
3832 // Compile uniform buffer with large array member.
TEST_P(WebGL2UniformBufferTest,LargeArrayOfStructs)3833 TEST_P(WebGL2UniformBufferTest, LargeArrayOfStructs)
3834 {
3835 constexpr char kVertexShader[] = R"(
3836 struct InstancingData
3837 {
3838 vec4 transformation;
3839 };
3840
3841 layout(std140) uniform InstanceBlock
3842 {
3843 InstancingData instances[MAX_INSTANCE_COUNT];
3844 };
3845
3846 void main()
3847 {
3848 gl_Position = vec4(1.0) * instances[gl_InstanceID].transformation[0];
3849 })";
3850
3851 constexpr char kFragmentShader[] = R"(#version 300 es
3852 precision mediump float;
3853 out vec4 outFragColor;
3854 void main()
3855 {
3856 outFragColor = vec4(0.0);
3857 })";
3858
3859 int maxUniformBlockSize;
3860 glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
3861
3862 std::string vs = "#version 300 es\n#define MAX_INSTANCE_COUNT " +
3863 std::to_string(maxUniformBlockSize / 16) + kVertexShader;
3864
3865 ANGLE_GL_PROGRAM(program, vs.c_str(), kFragmentShader);
3866 }
3867
3868 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniformBufferTest);
3869 ANGLE_INSTANTIATE_TEST_ES3(UniformBufferTest);
3870
3871 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniformBlockWithOneLargeArrayMemberTest);
3872 ANGLE_INSTANTIATE_TEST_ES3(UniformBlockWithOneLargeArrayMemberTest);
3873
3874 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniformBufferTest31);
3875 ANGLE_INSTANTIATE_TEST_ES31(UniformBufferTest31);
3876
3877 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniformBufferMemoryTest);
3878 ANGLE_INSTANTIATE_TEST_ES3(UniformBufferMemoryTest);
3879
3880 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WebGL2UniformBufferTest);
3881 ANGLE_INSTANTIATE_TEST_ES3(WebGL2UniformBufferTest);
3882
3883 } // namespace
3884