blob: c415a33dfcf7fa4a4beaf2d047336f4b5ef17192 [file] [log] [blame]
Geoff Langc287ea62016-09-16 14:46:51 -04001//
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// WebGLCompatibilityTest.cpp : Tests of the GL_ANGLE_webgl_compatibility extension.
8
9#include "test_utils/ANGLETest.h"
10
11#include "test_utils/gl_raii.h"
12
13namespace angle
14{
15
16class WebGLCompatibilityTest : public ANGLETest
17{
18 protected:
19 WebGLCompatibilityTest()
20 {
21 setWindowWidth(128);
22 setWindowHeight(128);
23 setConfigRedBits(8);
24 setConfigGreenBits(8);
25 setConfigBlueBits(8);
26 setConfigAlphaBits(8);
27 setWebGLCompatibilityEnabled(true);
28 }
29
30 void SetUp() override
31 {
32 ANGLETest::SetUp();
Geoff Langc339c4e2016-11-29 10:37:36 -050033 glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
34 eglGetProcAddress("glRequestExtensionANGLE"));
Geoff Langc287ea62016-09-16 14:46:51 -040035 }
36
37 void TearDown() override { ANGLETest::TearDown(); }
38
Geoff Langc339c4e2016-11-29 10:37:36 -050039 PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
Geoff Langc287ea62016-09-16 14:46:51 -040040};
41
Corentin Wallezfd456442016-12-21 17:57:00 -050042class WebGL2CompatibilityTest : public WebGLCompatibilityTest
43{
44};
45
Geoff Langc287ea62016-09-16 14:46:51 -040046// Context creation would fail if EGL_ANGLE_create_context_webgl_compatibility was not available so
47// the GL extension should always be present
48TEST_P(WebGLCompatibilityTest, ExtensionStringExposed)
49{
50 EXPECT_TRUE(extensionEnabled("GL_ANGLE_webgl_compatibility"));
51}
52
53// Verify that all extension entry points are available
54TEST_P(WebGLCompatibilityTest, EntryPoints)
55{
Geoff Langc339c4e2016-11-29 10:37:36 -050056 if (extensionEnabled("GL_ANGLE_request_extension"))
Geoff Langc287ea62016-09-16 14:46:51 -040057 {
Geoff Langc339c4e2016-11-29 10:37:36 -050058 EXPECT_NE(nullptr, eglGetProcAddress("glRequestExtensionANGLE"));
Geoff Langc287ea62016-09-16 14:46:51 -040059 }
60}
61
62// WebGL 1 allows GL_DEPTH_STENCIL_ATTACHMENT as a valid binding point. Make sure it is usable,
63// even in ES2 contexts.
64TEST_P(WebGLCompatibilityTest, DepthStencilBindingPoint)
65{
66 GLRenderbuffer renderbuffer;
67 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
68 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
69
70 GLFramebuffer framebuffer;
71 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
72 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
73 renderbuffer.get());
74
75 EXPECT_GL_NO_ERROR();
76}
77
78// Test that attempting to enable an extension that doesn't exist generates GL_INVALID_OPERATION
79TEST_P(WebGLCompatibilityTest, EnableExtensionValidation)
80{
Geoff Langc339c4e2016-11-29 10:37:36 -050081 glRequestExtensionANGLE("invalid_extension_string");
Geoff Langc287ea62016-09-16 14:46:51 -040082 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
83}
84
85// Test enabling the GL_OES_element_index_uint extension
86TEST_P(WebGLCompatibilityTest, EnableExtensionUintIndices)
87{
88 if (getClientMajorVersion() != 2)
89 {
90 // This test only works on ES2 where uint indices are not available by default
91 return;
92 }
93
94 EXPECT_FALSE(extensionEnabled("GL_OES_element_index_uint"));
95
96 GLBuffer indexBuffer;
97 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
98
99 GLuint data[] = {0, 1, 2, 1, 3, 2};
100 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
101
102 ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
103 "void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
104 glUseProgram(program.get());
105
106 glDrawElements(GL_TRIANGLES, 2, GL_UNSIGNED_INT, nullptr);
107 EXPECT_GL_ERROR(GL_INVALID_ENUM);
108
Geoff Langc339c4e2016-11-29 10:37:36 -0500109 if (extensionRequestable("GL_OES_element_index_uint"))
Geoff Langc287ea62016-09-16 14:46:51 -0400110 {
Geoff Langc339c4e2016-11-29 10:37:36 -0500111 glRequestExtensionANGLE("GL_OES_element_index_uint");
Geoff Langc287ea62016-09-16 14:46:51 -0400112 EXPECT_GL_NO_ERROR();
113 EXPECT_TRUE(extensionEnabled("GL_OES_element_index_uint"));
114
115 glDrawElements(GL_TRIANGLES, 2, GL_UNSIGNED_INT, nullptr);
116 EXPECT_GL_NO_ERROR();
117 }
118}
119
Bryan Bernhart87c182e2016-11-02 11:23:22 -0700120// Verify that shaders are of a compatible spec when the extension is enabled.
121TEST_P(WebGLCompatibilityTest, ExtensionCompilerSpec)
122{
123 EXPECT_TRUE(extensionEnabled("GL_ANGLE_webgl_compatibility"));
124
125 // Use of reserved _webgl prefix should fail when the shader specification is for WebGL.
126 const std::string &vert =
127 "struct Foo {\n"
128 " int _webgl_bar;\n"
129 "};\n"
130 "void main()\n"
131 "{\n"
132 " Foo foo = Foo(1);\n"
133 "}";
134
135 // Default fragement shader.
136 const std::string &frag =
137 "void main()\n"
138 "{\n"
139 " gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n"
140 "}";
141
142 GLuint program = CompileProgram(vert, frag);
143 EXPECT_EQ(0u, program);
144 glDeleteProgram(program);
145}
146
Corentin Wallez327411e2016-12-09 11:09:17 -0500147// Test that client-side array buffers are forbidden in WebGL mode
148TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBuffer)
149{
150 const std::string &vert =
151 "attribute vec3 a_pos;\n"
152 "void main()\n"
153 "{\n"
154 " gl_Position = vec4(a_pos, 1.0);\n"
155 "}\n";
156
157 const std::string &frag =
158 "precision highp float;\n"
159 "void main()\n"
160 "{\n"
161 " gl_FragColor = vec4(1.0);\n"
162 "}\n";
163
164 ANGLE_GL_PROGRAM(program, vert, frag);
165
166 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
167 ASSERT_NE(-1, posLocation);
168 glUseProgram(program.get());
169
170 const auto &vertices = GetQuadVertices();
Corentin Wallezfd456442016-12-21 17:57:00 -0500171 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 4, vertices.data());
Corentin Wallez327411e2016-12-09 11:09:17 -0500172 glEnableVertexAttribArray(posLocation);
173
174 ASSERT_GL_NO_ERROR();
175 glDrawArrays(GL_TRIANGLES, 0, 6);
176 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
177}
178
179// Test that client-side element array buffers are forbidden in WebGL mode
180TEST_P(WebGLCompatibilityTest, ForbidsClientSideElementBuffer)
181{
182 const std::string &vert =
183 "attribute vec3 a_pos;\n"
184 "void main()\n"
185 "{\n"
186 " gl_Position = vec4(a_pos, 1.0);\n"
187 "}\n";
188
189 const std::string &frag =
190 "precision highp float;\n"
191 "void main()\n"
192 "{\n"
193 " gl_FragColor = vec4(1.0);\n"
194 "}\n";
195
196 ANGLE_GL_PROGRAM(program, vert, frag);
197
198 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
199 ASSERT_NE(-1, posLocation);
200 glUseProgram(program.get());
201
202 const auto &vertices = GetQuadVertices();
203
204 GLBuffer vertexBuffer;
205 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
206 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
207 GL_STATIC_DRAW);
208
209 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
210 glEnableVertexAttribArray(posLocation);
211
212 const GLubyte indices[] = {0, 1, 2, 3, 4, 5};
213
214 ASSERT_GL_NO_ERROR();
215 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
216 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
217}
218
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500219// Tests the WebGL requirement of having the same stencil mask, writemask and ref for fron and back
220TEST_P(WebGLCompatibilityTest, RequiresSameStencilMaskAndRef)
221{
222 // Run the test in an FBO to make sure we have some stencil bits.
223 GLRenderbuffer renderbuffer;
224 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
225 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
226
227 GLFramebuffer framebuffer;
228 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
229 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
230 renderbuffer.get());
231
232 ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
233 "void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
234 glUseProgram(program.get());
235 ASSERT_GL_NO_ERROR();
236
237 // Having ref and mask the same for front and back is valid.
238 glStencilMask(255);
239 glStencilFunc(GL_ALWAYS, 0, 255);
240 glDrawArrays(GL_TRIANGLES, 0, 6);
241 ASSERT_GL_NO_ERROR();
242
243 // Having a different front - back write mask generates an error.
244 glStencilMaskSeparate(GL_FRONT, 1);
245 glDrawArrays(GL_TRIANGLES, 0, 6);
246 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
247
248 // Setting both write masks separately to the same value is valid.
249 glStencilMaskSeparate(GL_BACK, 1);
250 glDrawArrays(GL_TRIANGLES, 0, 6);
251 ASSERT_GL_NO_ERROR();
252
253 // Having a different stencil front - back mask generates an error
254 glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0, 1);
255 glDrawArrays(GL_TRIANGLES, 0, 6);
256 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
257
258 // Setting both masks separately to the same value is valid.
259 glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 1);
260 glDrawArrays(GL_TRIANGLES, 0, 6);
261 ASSERT_GL_NO_ERROR();
262
263 // Having a different stencil front - back reference generates an error
264 glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 255, 1);
265 glDrawArrays(GL_TRIANGLES, 0, 6);
266 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
267
268 // Setting both references separately to the same value is valid.
269 glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 255, 1);
270 glDrawArrays(GL_TRIANGLES, 0, 6);
271 ASSERT_GL_NO_ERROR();
272
273 // Using different stencil funcs, everything being equal is valid.
274 glStencilFuncSeparate(GL_BACK, GL_NEVER, 255, 1);
275 glDrawArrays(GL_TRIANGLES, 0, 6);
276 ASSERT_GL_NO_ERROR();
277}
278
Corentin Wallez506fc9c2016-12-21 16:53:33 -0500279// Test that GL_FIXED is forbidden
280TEST_P(WebGLCompatibilityTest, ForbidsGLFixed)
281{
282 GLBuffer buffer;
283 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
284 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
285
286 glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
287 ASSERT_GL_NO_ERROR();
288
289 glVertexAttribPointer(0, 1, GL_FIXED, GL_FALSE, 0, nullptr);
290 EXPECT_GL_ERROR(GL_INVALID_ENUM);
291}
292
293// Test the WebGL limit of 255 for the attribute stride
294TEST_P(WebGLCompatibilityTest, MaxStride)
295{
296 GLBuffer buffer;
297 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
298 glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
299
300 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 255, nullptr);
301 ASSERT_GL_NO_ERROR();
302
303 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 256, nullptr);
304 EXPECT_GL_ERROR(GL_INVALID_VALUE);
305}
306
Corentin Wallezfd456442016-12-21 17:57:00 -0500307// Test the checks for OOB reads in the vertex buffers, non-instanced version
308TEST_P(WebGLCompatibilityTest, DrawArraysBufferOutOfBoundsNonInstanced)
309{
310 const std::string &vert =
311 "attribute float a_pos;\n"
312 "void main()\n"
313 "{\n"
314 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
315 "}\n";
316
317 const std::string &frag =
318 "precision highp float;\n"
319 "void main()\n"
320 "{\n"
321 " gl_FragColor = vec4(1.0);\n"
322 "}\n";
323
324 ANGLE_GL_PROGRAM(program, vert, frag);
325
326 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
327 ASSERT_NE(-1, posLocation);
328 glUseProgram(program.get());
329
330 GLBuffer buffer;
331 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
332 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
333
334 glEnableVertexAttribArray(posLocation);
335
336 const uint8_t* zeroOffset = nullptr;
337
338 // Test touching the last element is valid.
339 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
340 glDrawArrays(GL_POINTS, 0, 4);
341 ASSERT_GL_NO_ERROR();
342
343 // Test touching the last element + 1 is invalid.
344 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
345 glDrawArrays(GL_POINTS, 0, 4);
346 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
347
348 // Test touching the last element is valid, using a stride.
349 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
350 glDrawArrays(GL_POINTS, 0, 4);
351 ASSERT_GL_NO_ERROR();
352
353 // Test touching the last element + 1 is invalid, using a stride.
354 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
355 glDrawArrays(GL_POINTS, 0, 4);
356 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
357
358 // Test any offset is valid if no vertices are drawn.
359 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
360 glDrawArrays(GL_POINTS, 0, 0);
361 ASSERT_GL_NO_ERROR();
362}
363
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500364// Test the checks for OOB reads in the index buffer
365TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInIndexBuffer)
Geoff Lang5f319a42017-01-09 16:49:19 -0500366{
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500367 const std::string &vert =
368 "attribute float a_pos;\n"
369 "void main()\n"
370 "{\n"
371 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
372 "}\n";
Geoff Lang5f319a42017-01-09 16:49:19 -0500373
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500374 const std::string &frag =
375 "precision highp float;\n"
376 "void main()\n"
377 "{\n"
378 " gl_FragColor = vec4(1.0);\n"
379 "}\n";
380
381 ANGLE_GL_PROGRAM(program, vert, frag);
382
383 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
384 ASSERT_NE(-1, posLocation);
385 glUseProgram(program.get());
386
387 GLBuffer vertexBuffer;
388 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
389 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
390
391 glEnableVertexAttribArray(posLocation);
392
393 const uint8_t *zeroOffset = nullptr;
394 const uint8_t zeroIndices[] = {0, 0, 0, 0, 0, 0, 0, 0};
395
396 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset);
397
398 GLBuffer indexBuffer;
399 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
400 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(zeroIndices), zeroIndices, GL_STATIC_DRAW);
Geoff Lang5f319a42017-01-09 16:49:19 -0500401 ASSERT_GL_NO_ERROR();
402
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500403 // Test touching the last index is valid
404 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 4);
405 ASSERT_GL_NO_ERROR();
Geoff Lang5f319a42017-01-09 16:49:19 -0500406
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500407 // Test touching the last + 1 element is invalid
408 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 5);
409 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Geoff Lang5f319a42017-01-09 16:49:19 -0500410
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500411 // Test any offset if valid if count is zero
412 glDrawElements(GL_POINTS, 0, GL_UNSIGNED_BYTE, zeroOffset + 42);
413 ASSERT_GL_NO_ERROR();
Geoff Lang5f319a42017-01-09 16:49:19 -0500414}
415
Corentin Wallezfd456442016-12-21 17:57:00 -0500416// Test the checks for OOB reads in the vertex buffers, instanced version
417TEST_P(WebGL2CompatibilityTest, DrawArraysBufferOutOfBoundsInstanced)
418{
419 const std::string &vert =
420 "attribute float a_pos;\n"
421 "void main()\n"
422 "{\n"
423 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
424 "}\n";
425
426 const std::string &frag =
427 "precision highp float;\n"
428 "void main()\n"
429 "{\n"
430 " gl_FragColor = vec4(1.0);\n"
431 "}\n";
432
433 ANGLE_GL_PROGRAM(program, vert, frag);
434
435 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
436 ASSERT_NE(-1, posLocation);
437 glUseProgram(program.get());
438
439 GLBuffer buffer;
440 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
441 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
442
443 glEnableVertexAttribArray(posLocation);
444 glVertexAttribDivisor(posLocation, 1);
445
446 const uint8_t* zeroOffset = nullptr;
447
448 // Test touching the last element is valid.
449 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
450 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
451 ASSERT_GL_NO_ERROR();
452
453 // Test touching the last element + 1 is invalid.
454 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
455 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
456 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
457
458 // Test touching the last element is valid, using a stride.
459 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
460 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
461 ASSERT_GL_NO_ERROR();
462
463 // Test touching the last element + 1 is invalid, using a stride.
464 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
465 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
466 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
467
468 // Test any offset is valid if no vertices are drawn.
469 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
470 glDrawArraysInstanced(GL_POINTS, 0, 1, 0);
471 ASSERT_GL_NO_ERROR();
472}
473
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500474// Tests that NPOT is not enabled by default in WebGL 1 and that it can be enabled
475TEST_P(WebGLCompatibilityTest, NPOT)
476{
477 EXPECT_FALSE(extensionEnabled("GL_OES_texture_npot"));
478
479 // Create a texture and set an NPOT mip 0, should always be acceptable.
480 GLTexture texture;
481 glBindTexture(GL_TEXTURE_2D, texture.get());
482 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
483 ASSERT_GL_NO_ERROR();
484
485 // Try setting an NPOT mip 1 and verify the error if WebGL 1
486 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
487 if (getClientMajorVersion() < 3)
488 {
489 ASSERT_GL_ERROR(GL_INVALID_VALUE);
490 }
491 else
492 {
493 ASSERT_GL_NO_ERROR();
494 }
495
496 if (extensionRequestable("GL_OES_texture_npot"))
497 {
498 glRequestExtensionANGLE("GL_OES_texture_npot");
499 ASSERT_GL_NO_ERROR();
500
501 // Try again to set NPOT mip 1
502 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
503 ASSERT_GL_NO_ERROR();
504 }
505}
506
Jamie Madilla4595b82017-01-11 17:36:34 -0500507// Tests that a rendering feedback loop triggers a GL error under WebGL.
508// Based on WebGL test conformance/renderbuffers/feedback-loop.html.
509TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
510{
511 const std::string vertexShader =
512 "attribute vec4 a_position;\n"
513 "varying vec2 v_texCoord;\n"
514 "void main() {\n"
515 " gl_Position = a_position;\n"
516 " v_texCoord = (a_position.xy * 0.5) + 0.5;\n"
517 "}\n";
518
519 const std::string fragmentShader =
520 "precision mediump float;\n"
521 "varying vec2 v_texCoord;\n"
522 "uniform sampler2D u_texture;\n"
523 "void main() {\n"
524 " // Shader swizzles color channels so we can tell if the draw succeeded.\n"
525 " gl_FragColor = texture2D(u_texture, v_texCoord).gbra;\n"
526 "}\n";
527
528 GLTexture texture;
529 glBindTexture(GL_TEXTURE_2D, texture.get());
530 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red);
531 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
532 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
533 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
534 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
535
536 ASSERT_GL_NO_ERROR();
537
538 GLFramebuffer framebuffer;
539 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
540 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
541
542 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
543
544 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
545
546 GLint uniformLoc = glGetUniformLocation(program.get(), "u_texture");
547 ASSERT_NE(-1, uniformLoc);
548
549 glUseProgram(program.get());
550 glUniform1i(uniformLoc, 0);
551 glDisable(GL_BLEND);
552 glDisable(GL_DEPTH_TEST);
553 ASSERT_GL_NO_ERROR();
554
555 // Drawing with a texture that is also bound to the current framebuffer should fail
556 glBindTexture(GL_TEXTURE_2D, texture.get());
557 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
558 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
559
560 // Ensure that the texture contents did not change after the previous render
561 glBindFramebuffer(GL_FRAMEBUFFER, 0);
562 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
563 ASSERT_GL_NO_ERROR();
564 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
565
566 // Drawing when texture is bound to an inactive uniform should succeed
567 GLTexture texture2;
568 glBindTexture(GL_TEXTURE_2D, texture2.get());
569 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
570 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
571 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
572 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
573 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
574
575 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
576 glActiveTexture(GL_TEXTURE1);
577 glBindTexture(GL_TEXTURE_2D, texture.get());
578 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
579 ASSERT_GL_NO_ERROR();
580 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
581}
582
Jamie Madillf695a3a2017-01-11 17:36:35 -0500583// Test tests that texture copying feedback loops are properly rejected in WebGL.
584// Based on the WebGL test conformance/textures/misc/texture-copying-feedback-loops.html
585TEST_P(WebGLCompatibilityTest, TextureCopyingFeedbackLoops)
586{
587 GLTexture texture;
588 glBindTexture(GL_TEXTURE_2D, texture.get());
589 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
590 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
591 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
592 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
593 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
594
595 GLTexture texture2;
596 glBindTexture(GL_TEXTURE_2D, texture2.get());
597 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
598 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
599 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
600 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
601 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
602
603 GLFramebuffer framebuffer;
604 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
605 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
606
607 // framebuffer should be FRAMEBUFFER_COMPLETE.
608 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
609 ASSERT_GL_NO_ERROR();
610
611 // testing copyTexImage2D
612
613 // copyTexImage2D to same texture but different level
614 glBindTexture(GL_TEXTURE_2D, texture.get());
615 glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
616 EXPECT_GL_NO_ERROR();
617
618 // copyTexImage2D to same texture same level, invalid feedback loop
619 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
620 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
621
622 // copyTexImage2D to different texture
623 glBindTexture(GL_TEXTURE_2D, texture2.get());
624 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
625 EXPECT_GL_NO_ERROR();
626
627 // testing copyTexSubImage2D
628
629 // copyTexSubImage2D to same texture but different level
630 glBindTexture(GL_TEXTURE_2D, texture.get());
631 glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
632 EXPECT_GL_NO_ERROR();
633
634 // copyTexSubImage2D to same texture same level, invalid feedback loop
635 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
636 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
637
638 // copyTexSubImage2D to different texture
639 glBindTexture(GL_TEXTURE_2D, texture2.get());
640 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
641 EXPECT_GL_NO_ERROR();
642}
643
Bryan Bernhart58806562017-01-05 13:09:31 -0800644// Test for the max draw buffers and color attachments.
645TEST_P(WebGLCompatibilityTest, MaxDrawBuffersAttachmentPoints)
646{
647 // This test only applies to ES2.
648 if (getClientMajorVersion() != 2)
649 {
650 return;
651 }
652
653 GLFramebuffer fbo[2];
654 glBindFramebuffer(GL_FRAMEBUFFER, fbo[0].get());
655
656 // Test that is valid when we bind with a single attachment point.
657 GLTexture texture;
658 glBindTexture(GL_TEXTURE_2D, texture.get());
659 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
660 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
661 ASSERT_GL_NO_ERROR();
662
663 // Test that enabling the draw buffers extension will allow us to bind with a non-zero
664 // attachment point.
665 if (extensionRequestable("GL_EXT_draw_buffers"))
666 {
667 glRequestExtensionANGLE("GL_EXT_draw_buffers");
668 EXPECT_GL_NO_ERROR();
669 EXPECT_TRUE(extensionEnabled("GL_EXT_draw_buffers"));
670
671 glBindFramebuffer(GL_FRAMEBUFFER, fbo[1].get());
672
673 GLTexture texture2;
674 glBindTexture(GL_TEXTURE_2D, texture2.get());
675 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
676 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2.get(),
677 0);
678 ASSERT_GL_NO_ERROR();
679 }
680}
681
Corentin Wallez3f6d4df2017-01-30 18:04:36 -0500682// Test that the offset in the index buffer is forced to be a multiple of the element size
683TEST_P(WebGLCompatibilityTest, DrawElementsOffsetRestriction)
684{
685 const std::string &vert =
686 "attribute vec3 a_pos;\n"
687 "void main()\n"
688 "{\n"
689 " gl_Position = vec4(a_pos, 1.0);\n"
690 "}\n";
691
692 const std::string &frag =
693 "precision highp float;\n"
694 "void main()\n"
695 "{\n"
696 " gl_FragColor = vec4(1.0);\n"
697 "}\n";
698
699 ANGLE_GL_PROGRAM(program, vert, frag);
700
701 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
702 ASSERT_NE(-1, posLocation);
703 glUseProgram(program.get());
704
705 const auto &vertices = GetQuadVertices();
706
707 GLBuffer vertexBuffer;
708 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
709 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
710 GL_STATIC_DRAW);
711
712 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
713 glEnableVertexAttribArray(posLocation);
714
715 GLBuffer indexBuffer;
716 const GLubyte indices[] = {0, 0, 0, 0, 0, 0, 0};
717 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
718 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
719
720 ASSERT_GL_NO_ERROR();
721
722 const char *zeroIndices = nullptr;
723
724 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, zeroIndices);
725 ASSERT_GL_NO_ERROR();
726
727 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, zeroIndices);
728 ASSERT_GL_NO_ERROR();
729
730 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, zeroIndices + 1);
731 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
732}
733
734// Test that the offset and stride in the vertex buffer is forced to be a multiple of the element
735// size
736TEST_P(WebGLCompatibilityTest, VertexAttribPointerOffsetRestriction)
737{
738 const char *zeroOffset = nullptr;
739
740 // Base case, vector of two floats
741 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset);
742 ASSERT_GL_NO_ERROR();
743
744 // Test setting a non-multiple offset
745 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 1);
746 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
747 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 2);
748 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
749 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 3);
750 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
751
752 // Test setting a non-multiple stride
753 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 1, zeroOffset);
754 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
755 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2, zeroOffset);
756 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
757 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 3, zeroOffset);
758 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
759}
760
Geoff Langc287ea62016-09-16 14:46:51 -0400761// Use this to select which configurations (e.g. which renderer, which GLES major version) these
762// tests should be run against.
763ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,
764 ES2_D3D9(),
765 ES2_D3D11(),
766 ES3_D3D11(),
767 ES2_D3D11_FL9_3(),
768 ES2_OPENGL(),
769 ES3_OPENGL(),
770 ES2_OPENGLES(),
771 ES3_OPENGLES());
772
Corentin Wallezfd456442016-12-21 17:57:00 -0500773ANGLE_INSTANTIATE_TEST(WebGL2CompatibilityTest,
774 ES3_D3D11(),
775 ES3_OPENGL(),
776 ES3_OPENGLES());
777
Geoff Langc287ea62016-09-16 14:46:51 -0400778} // namespace