blob: b81014496ee0fadf979b0d7c960bbe1d8f4d00bf [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
Geoff Lang677bb6f2017-04-05 12:40:40 -040011#include "common/mathutil.h"
Geoff Langc287ea62016-09-16 14:46:51 -040012#include "test_utils/gl_raii.h"
13
Frank Henigman146e8a12017-03-02 23:22:37 -050014namespace
15{
16
17bool ConstantColorAndAlphaBlendFunctions(GLenum first, GLenum second)
18{
19 return (first == GL_CONSTANT_COLOR || first == GL_ONE_MINUS_CONSTANT_COLOR) &&
20 (second == GL_CONSTANT_ALPHA || second == GL_ONE_MINUS_CONSTANT_ALPHA);
21}
22
23void CheckBlendFunctions(GLenum src, GLenum dst)
24{
25 if (ConstantColorAndAlphaBlendFunctions(src, dst) ||
26 ConstantColorAndAlphaBlendFunctions(dst, src))
27 {
28 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
29 }
30 else
31 {
32 ASSERT_GL_NO_ERROR();
33 }
34}
35
Geoff Lang677bb6f2017-04-05 12:40:40 -040036// Extensions that affect the ability to use floating point textures
37constexpr const char *FloatingPointTextureExtensions[] = {
38 "",
39 "GL_EXT_texture_storage",
40 "GL_OES_texture_float",
41 "GL_OES_texture_float_linear",
42 "GL_OES_texture_half_float",
43 "GL_OES_texture_half_float_linear",
44 "GL_EXT_color_buffer_half_float",
45 "GL_EXT_color_buffer_float",
46 "GL_CHROMIUM_color_buffer_float_rgba",
47 "GL_CHROMIUM_color_buffer_float_rgb",
48};
49
Frank Henigman146e8a12017-03-02 23:22:37 -050050} // namespace
51
Geoff Langc287ea62016-09-16 14:46:51 -040052namespace angle
53{
54
55class WebGLCompatibilityTest : public ANGLETest
56{
57 protected:
58 WebGLCompatibilityTest()
59 {
60 setWindowWidth(128);
61 setWindowHeight(128);
62 setConfigRedBits(8);
63 setConfigGreenBits(8);
64 setConfigBlueBits(8);
65 setConfigAlphaBits(8);
66 setWebGLCompatibilityEnabled(true);
67 }
68
69 void SetUp() override
70 {
71 ANGLETest::SetUp();
Geoff Langc339c4e2016-11-29 10:37:36 -050072 glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
73 eglGetProcAddress("glRequestExtensionANGLE"));
Geoff Langc287ea62016-09-16 14:46:51 -040074 }
75
Geoff Lang677bb6f2017-04-05 12:40:40 -040076 template <typename T>
77 void TestFloatTextureFormat(GLenum internalFormat,
78 GLenum format,
79 GLenum type,
80 bool texturingEnabled,
81 bool linearSamplingEnabled,
82 bool renderingEnabled,
83 const T textureData[4],
84 const float floatData[4])
85 {
86 ASSERT_GL_NO_ERROR();
87
88 const std::string samplingVs =
89 "attribute vec4 position;\n"
90 "varying vec2 texcoord;\n"
91 "void main()\n"
92 "{\n"
93 " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
94 " texcoord = (position.xy * 0.5) + 0.5;\n"
95 "}\n";
96
97 const std::string samplingFs =
98 "precision mediump float;\n"
99 "uniform sampler2D tex;\n"
100 "uniform vec4 subtractor;\n"
101 "varying vec2 texcoord;\n"
102 "void main()\n"
103 "{\n"
104 " vec4 color = texture2D(tex, texcoord);\n"
105 " if (abs(color.r - subtractor.r) +\n"
106 " abs(color.g - subtractor.g) +\n"
107 " abs(color.b - subtractor.b) +\n"
108 " abs(color.a - subtractor.a) < 8.0)\n"
109 " {\n"
110 " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
111 " }\n"
112 " else\n"
113 " {\n"
114 " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
115 " }\n"
116 "}\n";
117
118 ANGLE_GL_PROGRAM(samplingProgram, samplingVs, samplingFs);
119 glUseProgram(samplingProgram.get());
120
121 GLRenderbuffer rbo;
122 glBindRenderbuffer(GL_RENDERBUFFER, rbo.get());
123 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
124
125 GLFramebuffer fbo;
126 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
127 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo.get());
128
129 GLTexture texture;
130 glBindTexture(GL_TEXTURE_2D, texture.get());
131
132 if (internalFormat == format)
133 {
134 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0, format, type, textureData);
135 }
136 else
137 {
138 if (getClientMajorVersion() >= 3)
139 {
140 glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, 1, 1);
141 }
142 else
143 {
144 ASSERT_TRUE(extensionEnabled("GL_EXT_texture_storage"));
145 glTexStorage2DEXT(GL_TEXTURE_2D, 1, internalFormat, 1, 1);
146 }
147 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, format, type, textureData);
148 }
149
150 if (!texturingEnabled)
151 {
152 // Depending on the entry point and client version, different errors may be generated
153 ASSERT_GLENUM_NE(GL_NO_ERROR, glGetError());
154
155 // Two errors may be generated in the glTexStorage + glTexSubImage case, clear the
156 // second error
157 glGetError();
158
159 return;
160 }
161 ASSERT_GL_NO_ERROR();
162
163 glUniform1i(glGetUniformLocation(samplingProgram.get(), "tex"), 0);
164 glUniform4fv(glGetUniformLocation(samplingProgram.get(), "subtractor"), 1, floatData);
165
166 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
167 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
168 drawQuad(samplingProgram.get(), "position", 0.5f, 1.0f, true);
169 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
170
171 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
172 drawQuad(samplingProgram.get(), "position", 0.5f, 1.0f, true);
173
174 if (linearSamplingEnabled)
175 {
176 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
177 }
178 else
179 {
180 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
181 }
182
183 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(),
184 0);
185 glBindTexture(GL_TEXTURE_2D, 0);
186 if (!renderingEnabled)
187 {
188 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
189 glCheckFramebufferStatus(GL_FRAMEBUFFER));
190 return;
191 }
192 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
193
194 const std::string renderingVs =
195 "attribute vec4 position;\n"
196 "void main()\n"
197 "{\n"
198 " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
199 "}\n";
200
201 const std::string renderingFs =
202 "precision mediump float;\n"
203 "uniform vec4 writeValue;\n"
204 "void main()\n"
205 "{\n"
206 " gl_FragColor = writeValue;\n"
207 "}\n";
208
209 ANGLE_GL_PROGRAM(renderingProgram, renderingVs, renderingFs);
210 glUseProgram(renderingProgram.get());
211
212 glUniform4fv(glGetUniformLocation(renderingProgram.get(), "writeValue"), 1, floatData);
213
214 drawQuad(renderingProgram.get(), "position", 0.5f, 1.0f, true);
215
216 EXPECT_PIXEL_COLOR32F_NEAR(
217 0, 0, GLColor32F(floatData[0], floatData[1], floatData[2], floatData[3]), 1.0f);
218 }
219
Jamie Madillcad97ee2017-02-02 18:52:44 -0500220 // Called from RenderingFeedbackLoopWithDrawBuffersEXT.
221 void drawBuffersEXTFeedbackLoop(GLuint program,
222 const std::array<GLenum, 2> &drawBuffers,
223 GLenum expectedError);
224
Jamie Madill07be8bf2017-02-02 19:59:57 -0500225 // Called from RenderingFeedbackLoopWithDrawBuffers.
226 void drawBuffersFeedbackLoop(GLuint program,
227 const std::array<GLenum, 2> &drawBuffers,
228 GLenum expectedError);
229
Geoff Langc339c4e2016-11-29 10:37:36 -0500230 PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
Geoff Langc287ea62016-09-16 14:46:51 -0400231};
232
Corentin Wallezfd456442016-12-21 17:57:00 -0500233class WebGL2CompatibilityTest : public WebGLCompatibilityTest
234{
235};
236
Geoff Langc287ea62016-09-16 14:46:51 -0400237// Context creation would fail if EGL_ANGLE_create_context_webgl_compatibility was not available so
238// the GL extension should always be present
239TEST_P(WebGLCompatibilityTest, ExtensionStringExposed)
240{
241 EXPECT_TRUE(extensionEnabled("GL_ANGLE_webgl_compatibility"));
242}
243
244// Verify that all extension entry points are available
245TEST_P(WebGLCompatibilityTest, EntryPoints)
246{
Geoff Langc339c4e2016-11-29 10:37:36 -0500247 if (extensionEnabled("GL_ANGLE_request_extension"))
Geoff Langc287ea62016-09-16 14:46:51 -0400248 {
Geoff Langc339c4e2016-11-29 10:37:36 -0500249 EXPECT_NE(nullptr, eglGetProcAddress("glRequestExtensionANGLE"));
Geoff Langc287ea62016-09-16 14:46:51 -0400250 }
251}
252
253// WebGL 1 allows GL_DEPTH_STENCIL_ATTACHMENT as a valid binding point. Make sure it is usable,
254// even in ES2 contexts.
255TEST_P(WebGLCompatibilityTest, DepthStencilBindingPoint)
256{
257 GLRenderbuffer renderbuffer;
258 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
259 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
260
261 GLFramebuffer framebuffer;
262 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
263 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
264 renderbuffer.get());
265
266 EXPECT_GL_NO_ERROR();
267}
268
269// Test that attempting to enable an extension that doesn't exist generates GL_INVALID_OPERATION
270TEST_P(WebGLCompatibilityTest, EnableExtensionValidation)
271{
Geoff Langc339c4e2016-11-29 10:37:36 -0500272 glRequestExtensionANGLE("invalid_extension_string");
Geoff Langc287ea62016-09-16 14:46:51 -0400273 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
274}
275
276// Test enabling the GL_OES_element_index_uint extension
277TEST_P(WebGLCompatibilityTest, EnableExtensionUintIndices)
278{
279 if (getClientMajorVersion() != 2)
280 {
281 // This test only works on ES2 where uint indices are not available by default
282 return;
283 }
284
285 EXPECT_FALSE(extensionEnabled("GL_OES_element_index_uint"));
286
287 GLBuffer indexBuffer;
288 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
289
290 GLuint data[] = {0, 1, 2, 1, 3, 2};
291 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
292
293 ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
294 "void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
295 glUseProgram(program.get());
296
Jamie Madille7b96342017-06-23 15:06:08 -0400297 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
Geoff Langc287ea62016-09-16 14:46:51 -0400298 EXPECT_GL_ERROR(GL_INVALID_ENUM);
299
Geoff Langc339c4e2016-11-29 10:37:36 -0500300 if (extensionRequestable("GL_OES_element_index_uint"))
Geoff Langc287ea62016-09-16 14:46:51 -0400301 {
Geoff Langc339c4e2016-11-29 10:37:36 -0500302 glRequestExtensionANGLE("GL_OES_element_index_uint");
Geoff Langc287ea62016-09-16 14:46:51 -0400303 EXPECT_GL_NO_ERROR();
304 EXPECT_TRUE(extensionEnabled("GL_OES_element_index_uint"));
305
Jamie Madille7b96342017-06-23 15:06:08 -0400306 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
Geoff Langc287ea62016-09-16 14:46:51 -0400307 EXPECT_GL_NO_ERROR();
308 }
309}
310
Geoff Langff5c63e2017-04-12 15:26:54 -0400311// Test enabling the GL_OES_standard_derivatives extension
312TEST_P(WebGLCompatibilityTest, EnableExtensionStandardDerivitives)
313{
314 EXPECT_FALSE(extensionEnabled("GL_OES_standard_derivatives"));
315
316 const std::string source =
317 "#extension GL_OES_standard_derivatives : require\n"
318 "void main() { gl_FragColor = vec4(dFdx(vec2(1.0, 1.0)).x, 1, 0, 1); }\n";
319 ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, source));
320
321 if (extensionRequestable("GL_OES_standard_derivatives"))
322 {
323 glRequestExtensionANGLE("GL_OES_standard_derivatives");
324 EXPECT_GL_NO_ERROR();
325 EXPECT_TRUE(extensionEnabled("GL_OES_standard_derivatives"));
326
327 GLuint shader = CompileShader(GL_FRAGMENT_SHADER, source);
328 ASSERT_NE(0u, shader);
329 glDeleteShader(shader);
330 }
331}
332
333// Test enabling the GL_EXT_shader_texture_lod extension
334TEST_P(WebGLCompatibilityTest, EnableExtensionTextureLOD)
335{
336 EXPECT_FALSE(extensionEnabled("GL_EXT_shader_texture_lod"));
337
338 const std::string source =
339 "#extension GL_EXT_shader_texture_lod : require\n"
340 "uniform sampler2D u_texture;\n"
341 "void main() {\n"
342 " gl_FragColor = texture2DGradEXT(u_texture, vec2(0.0, 0.0), vec2(0.0, 0.0), vec2(0.0, "
343 "0.0));\n"
344 "}\n";
345 ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, source));
346
347 if (extensionRequestable("GL_EXT_shader_texture_lod"))
348 {
349 glRequestExtensionANGLE("GL_EXT_shader_texture_lod");
350 EXPECT_GL_NO_ERROR();
351 EXPECT_TRUE(extensionEnabled("GL_EXT_shader_texture_lod"));
352
353 GLuint shader = CompileShader(GL_FRAGMENT_SHADER, source);
354 ASSERT_NE(0u, shader);
355 glDeleteShader(shader);
356 }
357}
358
359// Test enabling the GL_EXT_frag_depth extension
360TEST_P(WebGLCompatibilityTest, EnableExtensionFragDepth)
361{
362 EXPECT_FALSE(extensionEnabled("GL_EXT_frag_depth"));
363
364 const std::string source =
365 "#extension GL_EXT_frag_depth : require\n"
366 "void main() {\n"
367 " gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
368 " gl_FragDepthEXT = 1.0;\n"
369 "}\n";
370 ASSERT_EQ(0u, CompileShader(GL_FRAGMENT_SHADER, source));
371
372 if (extensionRequestable("GL_EXT_frag_depth"))
373 {
374 glRequestExtensionANGLE("GL_EXT_frag_depth");
375 EXPECT_GL_NO_ERROR();
376 EXPECT_TRUE(extensionEnabled("GL_EXT_frag_depth"));
377
378 GLuint shader = CompileShader(GL_FRAGMENT_SHADER, source);
379 ASSERT_NE(0u, shader);
380 glDeleteShader(shader);
381 }
382}
383
Geoff Langd7d526a2017-02-21 16:48:43 -0500384// Test enabling the GL_EXT_texture_filter_anisotropic extension
385TEST_P(WebGLCompatibilityTest, EnableExtensionTextureFilterAnisotropic)
386{
387 EXPECT_FALSE(extensionEnabled("GL_EXT_texture_filter_anisotropic"));
388
389 GLfloat maxAnisotropy = 0.0f;
390 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
391 EXPECT_GL_ERROR(GL_INVALID_ENUM);
392
393 GLTexture texture;
394 glBindTexture(GL_TEXTURE_2D, texture.get());
395 ASSERT_GL_NO_ERROR();
396
397 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
398 EXPECT_GL_ERROR(GL_INVALID_ENUM);
399
400 GLfloat currentAnisotropy = 0.0f;
401 glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &currentAnisotropy);
402 EXPECT_GL_ERROR(GL_INVALID_ENUM);
403
404 if (extensionRequestable("GL_EXT_texture_filter_anisotropic"))
405 {
406 glRequestExtensionANGLE("GL_EXT_texture_filter_anisotropic");
407 EXPECT_GL_NO_ERROR();
408 EXPECT_TRUE(extensionEnabled("GL_EXT_texture_filter_anisotropic"));
409
410 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy);
411 ASSERT_GL_NO_ERROR();
412 EXPECT_GE(maxAnisotropy, 2.0f);
413
414 glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &currentAnisotropy);
415 ASSERT_GL_NO_ERROR();
416 EXPECT_EQ(1.0f, currentAnisotropy);
417
418 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0f);
419 ASSERT_GL_NO_ERROR();
420 }
421}
422
Bryan Bernhart87c182e2016-11-02 11:23:22 -0700423// Verify that shaders are of a compatible spec when the extension is enabled.
424TEST_P(WebGLCompatibilityTest, ExtensionCompilerSpec)
425{
426 EXPECT_TRUE(extensionEnabled("GL_ANGLE_webgl_compatibility"));
427
428 // Use of reserved _webgl prefix should fail when the shader specification is for WebGL.
429 const std::string &vert =
430 "struct Foo {\n"
431 " int _webgl_bar;\n"
432 "};\n"
433 "void main()\n"
434 "{\n"
435 " Foo foo = Foo(1);\n"
436 "}";
437
438 // Default fragement shader.
439 const std::string &frag =
440 "void main()\n"
441 "{\n"
442 " gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n"
443 "}";
444
445 GLuint program = CompileProgram(vert, frag);
446 EXPECT_EQ(0u, program);
447 glDeleteProgram(program);
448}
449
Geoff Langa0e0aeb2017-04-12 15:06:29 -0400450// Verify that the context generates the correct error when the framebuffer attachments are
451// different sizes
452TEST_P(WebGLCompatibilityTest, FramebufferAttachmentSizeMissmatch)
453{
454 GLFramebuffer fbo;
455 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
456
457 GLTexture textures[2];
458 glBindTexture(GL_TEXTURE_2D, textures[0]);
459 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
460 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
461
462 ASSERT_GL_NO_ERROR();
463 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
464
465 GLRenderbuffer renderbuffer;
466 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
467 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 3, 3);
468 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
469
470 ASSERT_GL_NO_ERROR();
471 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
472 glCheckFramebufferStatus(GL_FRAMEBUFFER));
473
474 if (extensionRequestable("GL_EXT_draw_buffers"))
475 {
476 glRequestExtensionANGLE("GL_EXT_draw_buffers");
477 EXPECT_GL_NO_ERROR();
478 EXPECT_TRUE(extensionEnabled("GL_EXT_draw_buffers"));
479
480 glBindTexture(GL_TEXTURE_2D, textures[1]);
481 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
482 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textures[1], 0);
483 ASSERT_GL_NO_ERROR();
484
485 ASSERT_GL_NO_ERROR();
486 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
487 glCheckFramebufferStatus(GL_FRAMEBUFFER));
488
489 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
490
491 ASSERT_GL_NO_ERROR();
492 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
493
494 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
495
496 ASSERT_GL_NO_ERROR();
497 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS,
498 glCheckFramebufferStatus(GL_FRAMEBUFFER));
499 }
500}
501
Corentin Wallez327411e2016-12-09 11:09:17 -0500502// Test that client-side array buffers are forbidden in WebGL mode
503TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBuffer)
504{
505 const std::string &vert =
506 "attribute vec3 a_pos;\n"
507 "void main()\n"
508 "{\n"
509 " gl_Position = vec4(a_pos, 1.0);\n"
510 "}\n";
511
512 const std::string &frag =
513 "precision highp float;\n"
514 "void main()\n"
515 "{\n"
516 " gl_FragColor = vec4(1.0);\n"
517 "}\n";
518
519 ANGLE_GL_PROGRAM(program, vert, frag);
520
521 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
522 ASSERT_NE(-1, posLocation);
523 glUseProgram(program.get());
524
525 const auto &vertices = GetQuadVertices();
Corentin Wallezfd456442016-12-21 17:57:00 -0500526 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 4, vertices.data());
Corentin Wallez327411e2016-12-09 11:09:17 -0500527 glEnableVertexAttribArray(posLocation);
528
529 ASSERT_GL_NO_ERROR();
530 glDrawArrays(GL_TRIANGLES, 0, 6);
531 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
532}
533
534// Test that client-side element array buffers are forbidden in WebGL mode
535TEST_P(WebGLCompatibilityTest, ForbidsClientSideElementBuffer)
536{
537 const std::string &vert =
538 "attribute vec3 a_pos;\n"
539 "void main()\n"
540 "{\n"
541 " gl_Position = vec4(a_pos, 1.0);\n"
542 "}\n";
543
544 const std::string &frag =
545 "precision highp float;\n"
546 "void main()\n"
547 "{\n"
548 " gl_FragColor = vec4(1.0);\n"
549 "}\n";
550
551 ANGLE_GL_PROGRAM(program, vert, frag);
552
553 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
554 ASSERT_NE(-1, posLocation);
555 glUseProgram(program.get());
556
557 const auto &vertices = GetQuadVertices();
558
559 GLBuffer vertexBuffer;
560 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
561 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
562 GL_STATIC_DRAW);
563
564 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
565 glEnableVertexAttribArray(posLocation);
566
Corentin Wallez327411e2016-12-09 11:09:17 -0500567 ASSERT_GL_NO_ERROR();
Corentin Wallezded1b5a2017-03-09 18:58:48 -0500568
569 // Use the pointer with value of 1 for indices instead of an actual pointer because WebGL also
570 // enforces that the top bit of indices must be 0 (i.e. offset >= 0) and would generate
571 // GL_INVALID_VALUE in that case. Using a null pointer gets caught by another check.
572 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<const void*>(intptr_t(1)));
Corentin Wallez327411e2016-12-09 11:09:17 -0500573 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
574}
575
Corentin Wallez672f7f32017-06-15 17:42:17 -0400576// Test that client-side array buffers are forbidden even if the program doesn't use the attribute
577TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBufferEvenNotUsedOnes)
578{
579 const std::string &vert =
580 "void main()\n"
581 "{\n"
582 " gl_Position = vec4(1.0);\n"
583 "}\n";
584
585 const std::string &frag =
586 "precision highp float;\n"
587 "void main()\n"
588 "{\n"
589 " gl_FragColor = vec4(1.0);\n"
590 "}\n";
591
592 ANGLE_GL_PROGRAM(program, vert, frag);
593
594 glUseProgram(program.get());
595
596 const auto &vertices = GetQuadVertices();
597 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4, vertices.data());
598 glEnableVertexAttribArray(0);
599
600 ASSERT_GL_NO_ERROR();
601 glDrawArrays(GL_TRIANGLES, 0, 6);
602 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
603}
604
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500605// Tests the WebGL requirement of having the same stencil mask, writemask and ref for fron and back
606TEST_P(WebGLCompatibilityTest, RequiresSameStencilMaskAndRef)
607{
608 // Run the test in an FBO to make sure we have some stencil bits.
609 GLRenderbuffer renderbuffer;
610 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
611 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
612
613 GLFramebuffer framebuffer;
614 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
615 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
616 renderbuffer.get());
617
618 ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
619 "void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
620 glUseProgram(program.get());
621 ASSERT_GL_NO_ERROR();
622
623 // Having ref and mask the same for front and back is valid.
624 glStencilMask(255);
625 glStencilFunc(GL_ALWAYS, 0, 255);
626 glDrawArrays(GL_TRIANGLES, 0, 6);
627 ASSERT_GL_NO_ERROR();
628
629 // Having a different front - back write mask generates an error.
630 glStencilMaskSeparate(GL_FRONT, 1);
631 glDrawArrays(GL_TRIANGLES, 0, 6);
632 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
633
634 // Setting both write masks separately to the same value is valid.
635 glStencilMaskSeparate(GL_BACK, 1);
636 glDrawArrays(GL_TRIANGLES, 0, 6);
637 ASSERT_GL_NO_ERROR();
638
639 // Having a different stencil front - back mask generates an error
640 glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0, 1);
641 glDrawArrays(GL_TRIANGLES, 0, 6);
642 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
643
644 // Setting both masks separately to the same value is valid.
645 glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 1);
646 glDrawArrays(GL_TRIANGLES, 0, 6);
647 ASSERT_GL_NO_ERROR();
648
649 // Having a different stencil front - back reference generates an error
650 glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 255, 1);
651 glDrawArrays(GL_TRIANGLES, 0, 6);
652 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
653
654 // Setting both references separately to the same value is valid.
655 glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 255, 1);
656 glDrawArrays(GL_TRIANGLES, 0, 6);
657 ASSERT_GL_NO_ERROR();
658
659 // Using different stencil funcs, everything being equal is valid.
660 glStencilFuncSeparate(GL_BACK, GL_NEVER, 255, 1);
661 glDrawArrays(GL_TRIANGLES, 0, 6);
662 ASSERT_GL_NO_ERROR();
663}
664
Corentin Wallez506fc9c2016-12-21 16:53:33 -0500665// Test that GL_FIXED is forbidden
666TEST_P(WebGLCompatibilityTest, ForbidsGLFixed)
667{
668 GLBuffer buffer;
669 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
670 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
671
672 glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
673 ASSERT_GL_NO_ERROR();
674
675 glVertexAttribPointer(0, 1, GL_FIXED, GL_FALSE, 0, nullptr);
676 EXPECT_GL_ERROR(GL_INVALID_ENUM);
677}
678
679// Test the WebGL limit of 255 for the attribute stride
680TEST_P(WebGLCompatibilityTest, MaxStride)
681{
682 GLBuffer buffer;
683 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
684 glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
685
686 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 255, nullptr);
687 ASSERT_GL_NO_ERROR();
688
689 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 256, nullptr);
690 EXPECT_GL_ERROR(GL_INVALID_VALUE);
691}
692
Corentin Wallezfd456442016-12-21 17:57:00 -0500693// Test the checks for OOB reads in the vertex buffers, non-instanced version
694TEST_P(WebGLCompatibilityTest, DrawArraysBufferOutOfBoundsNonInstanced)
695{
696 const std::string &vert =
697 "attribute float a_pos;\n"
698 "void main()\n"
699 "{\n"
700 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
701 "}\n";
702
703 const std::string &frag =
704 "precision highp float;\n"
705 "void main()\n"
706 "{\n"
707 " gl_FragColor = vec4(1.0);\n"
708 "}\n";
709
710 ANGLE_GL_PROGRAM(program, vert, frag);
711
712 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
713 ASSERT_NE(-1, posLocation);
714 glUseProgram(program.get());
715
716 GLBuffer buffer;
717 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
718 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
719
720 glEnableVertexAttribArray(posLocation);
721
722 const uint8_t* zeroOffset = nullptr;
723
724 // Test touching the last element is valid.
725 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
726 glDrawArrays(GL_POINTS, 0, 4);
727 ASSERT_GL_NO_ERROR();
728
729 // Test touching the last element + 1 is invalid.
730 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
731 glDrawArrays(GL_POINTS, 0, 4);
732 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
733
734 // Test touching the last element is valid, using a stride.
735 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
736 glDrawArrays(GL_POINTS, 0, 4);
737 ASSERT_GL_NO_ERROR();
738
739 // Test touching the last element + 1 is invalid, using a stride.
740 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
741 glDrawArrays(GL_POINTS, 0, 4);
742 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
743
744 // Test any offset is valid if no vertices are drawn.
745 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
746 glDrawArrays(GL_POINTS, 0, 0);
747 ASSERT_GL_NO_ERROR();
748}
749
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500750// Test the checks for OOB reads in the index buffer
751TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInIndexBuffer)
Geoff Lang5f319a42017-01-09 16:49:19 -0500752{
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500753 const std::string &vert =
754 "attribute float a_pos;\n"
755 "void main()\n"
756 "{\n"
757 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
758 "}\n";
Geoff Lang5f319a42017-01-09 16:49:19 -0500759
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500760 const std::string &frag =
761 "precision highp float;\n"
762 "void main()\n"
763 "{\n"
764 " gl_FragColor = vec4(1.0);\n"
765 "}\n";
766
767 ANGLE_GL_PROGRAM(program, vert, frag);
768
769 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
770 ASSERT_NE(-1, posLocation);
771 glUseProgram(program.get());
772
773 GLBuffer vertexBuffer;
774 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
775 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
776
777 glEnableVertexAttribArray(posLocation);
778
779 const uint8_t *zeroOffset = nullptr;
780 const uint8_t zeroIndices[] = {0, 0, 0, 0, 0, 0, 0, 0};
781
782 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset);
783
784 GLBuffer indexBuffer;
785 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
786 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(zeroIndices), zeroIndices, GL_STATIC_DRAW);
Geoff Lang5f319a42017-01-09 16:49:19 -0500787 ASSERT_GL_NO_ERROR();
788
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500789 // Test touching the last index is valid
790 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 4);
791 ASSERT_GL_NO_ERROR();
Geoff Lang5f319a42017-01-09 16:49:19 -0500792
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500793 // Test touching the last + 1 element is invalid
794 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 5);
795 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Geoff Lang5f319a42017-01-09 16:49:19 -0500796
Corentin Wallez0844f2d2017-01-31 17:02:59 -0500797 // Test any offset if valid if count is zero
798 glDrawElements(GL_POINTS, 0, GL_UNSIGNED_BYTE, zeroOffset + 42);
799 ASSERT_GL_NO_ERROR();
Corentin Wallezfe9306a2017-02-01 17:41:05 -0500800
801 // Test touching the first index is valid
802 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 4);
803 ASSERT_GL_NO_ERROR();
804
805 // Test touching the first - 1 index is invalid
806 // The error ha been specified to be INVALID_VALUE instead of INVALID_OPERATION because it was
807 // the historic behavior of WebGL implementations
808 glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset - 1);
809 EXPECT_GL_ERROR(GL_INVALID_VALUE);
Geoff Lang5f319a42017-01-09 16:49:19 -0500810}
811
Frank Henigman6137ddc2017-02-10 18:55:07 -0500812// Test depth range with 'near' more or less than 'far.'
813TEST_P(WebGLCompatibilityTest, DepthRange)
814{
815 glDepthRangef(0, 1);
816 ASSERT_GL_NO_ERROR();
817
818 glDepthRangef(.5, .5);
819 ASSERT_GL_NO_ERROR();
820
821 glDepthRangef(1, 0);
822 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
823}
824
Frank Henigman146e8a12017-03-02 23:22:37 -0500825// Test all blend function combinations.
826// In WebGL it is invalid to combine constant color with constant alpha.
827TEST_P(WebGLCompatibilityTest, BlendWithConstantColor)
828{
829 constexpr GLenum srcFunc[] = {
830 GL_ZERO,
831 GL_ONE,
832 GL_SRC_COLOR,
833 GL_ONE_MINUS_SRC_COLOR,
834 GL_DST_COLOR,
835 GL_ONE_MINUS_DST_COLOR,
836 GL_SRC_ALPHA,
837 GL_ONE_MINUS_SRC_ALPHA,
838 GL_DST_ALPHA,
839 GL_ONE_MINUS_DST_ALPHA,
840 GL_CONSTANT_COLOR,
841 GL_ONE_MINUS_CONSTANT_COLOR,
842 GL_CONSTANT_ALPHA,
843 GL_ONE_MINUS_CONSTANT_ALPHA,
844 GL_SRC_ALPHA_SATURATE,
845 };
846
847 constexpr GLenum dstFunc[] = {
848 GL_ZERO, GL_ONE,
849 GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
850 GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR,
851 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
852 GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA,
853 GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR,
854 GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA,
855 };
856
857 for (GLenum src : srcFunc)
858 {
859 for (GLenum dst : dstFunc)
860 {
861 glBlendFunc(src, dst);
862 CheckBlendFunctions(src, dst);
863 glBlendFuncSeparate(src, dst, GL_ONE, GL_ONE);
864 CheckBlendFunctions(src, dst);
865 }
866 }
867}
868
Geoff Langfc32e8b2017-05-31 14:16:59 -0400869// Test that binding/querying uniforms and attributes with invalid names generates errors
870TEST_P(WebGLCompatibilityTest, InvalidAttributeAndUniformNames)
871{
872 const std::string validAttribName =
873 "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
874 const std::string validUniformName =
875 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890";
Geoff Langa71a98e2017-06-19 15:15:00 -0400876 std::vector<char> invalidSet = {'"', '$', '`', '@', '\''};
877 if (getClientMajorVersion() < 3)
878 {
879 invalidSet.push_back('\\');
880 }
Geoff Langfc32e8b2017-05-31 14:16:59 -0400881
882 std::string vert = "attribute float ";
883 vert += validAttribName;
884 vert +=
885 ";\n"
886 "void main()\n"
887 "{\n"
888 " gl_Position = vec4(1.0);\n"
889 "}\n";
890
891 std::string frag =
892 "precision highp float;\n"
893 "uniform vec4 ";
894 frag += validUniformName;
895 frag +=
896 ";\n"
897 "void main()\n"
898 "{\n"
899 " gl_FragColor = vec4(1.0);\n"
900 "}\n";
901
902 ANGLE_GL_PROGRAM(program, vert, frag);
903 EXPECT_GL_NO_ERROR();
904
905 for (char invalidChar : invalidSet)
906 {
907 std::string invalidName = validAttribName + invalidChar;
908 glGetAttribLocation(program, invalidName.c_str());
909 EXPECT_GL_ERROR(GL_INVALID_VALUE)
910 << "glGetAttribLocation unexpectedly succeeded for name \"" << invalidName << "\".";
911
912 glBindAttribLocation(program, 0, invalidName.c_str());
913 EXPECT_GL_ERROR(GL_INVALID_VALUE)
914 << "glBindAttribLocation unexpectedly succeeded for name \"" << invalidName << "\".";
915 }
916
917 for (char invalidChar : invalidSet)
918 {
919 std::string invalidName = validUniformName + invalidChar;
920 glGetUniformLocation(program, invalidName.c_str());
921 EXPECT_GL_ERROR(GL_INVALID_VALUE)
922 << "glGetUniformLocation unexpectedly succeeded for name \"" << invalidName << "\".";
923 }
924
925 for (char invalidChar : invalidSet)
926 {
927 std::string invalidAttribName = validAttribName + invalidChar;
928 const char *invalidVert[] = {
929 "attribute float ",
930 invalidAttribName.c_str(),
931 ";\n",
932 "void main()\n",
933 "{\n",
934 " gl_Position = vec4(1.0);\n",
935 "}\n",
936 };
937
938 GLuint shader = glCreateShader(GL_VERTEX_SHADER);
939 glShaderSource(shader, static_cast<GLsizei>(ArraySize(invalidVert)), invalidVert, nullptr);
940 EXPECT_GL_ERROR(GL_INVALID_VALUE);
941 glDeleteShader(shader);
942 }
943}
944
Corentin Wallezfd456442016-12-21 17:57:00 -0500945// Test the checks for OOB reads in the vertex buffers, instanced version
946TEST_P(WebGL2CompatibilityTest, DrawArraysBufferOutOfBoundsInstanced)
947{
948 const std::string &vert =
949 "attribute float a_pos;\n"
Geoff Lang407d4e72017-04-12 14:54:11 -0400950 "attribute float a_w;\n"
Corentin Wallezfd456442016-12-21 17:57:00 -0500951 "void main()\n"
952 "{\n"
Geoff Lang407d4e72017-04-12 14:54:11 -0400953 " gl_Position = vec4(a_pos, a_pos, a_pos, a_w);\n"
Corentin Wallezfd456442016-12-21 17:57:00 -0500954 "}\n";
955
956 const std::string &frag =
957 "precision highp float;\n"
958 "void main()\n"
959 "{\n"
960 " gl_FragColor = vec4(1.0);\n"
961 "}\n";
962
963 ANGLE_GL_PROGRAM(program, vert, frag);
964
965 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
966 ASSERT_NE(-1, posLocation);
Geoff Lang407d4e72017-04-12 14:54:11 -0400967
968 GLint wLocation = glGetAttribLocation(program.get(), "a_w");
969 ASSERT_NE(-1, wLocation);
970
Corentin Wallezfd456442016-12-21 17:57:00 -0500971 glUseProgram(program.get());
972
973 GLBuffer buffer;
974 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
975 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
976
977 glEnableVertexAttribArray(posLocation);
978 glVertexAttribDivisor(posLocation, 1);
979
Geoff Lang407d4e72017-04-12 14:54:11 -0400980 glEnableVertexAttribArray(wLocation);
981 glVertexAttribPointer(wLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
982 glVertexAttribDivisor(wLocation, 0);
983
Corentin Wallezfd456442016-12-21 17:57:00 -0500984 const uint8_t* zeroOffset = nullptr;
985
986 // Test touching the last element is valid.
987 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 12);
988 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
989 ASSERT_GL_NO_ERROR();
990
991 // Test touching the last element + 1 is invalid.
992 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 13);
993 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
994 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
995
996 // Test touching the last element is valid, using a stride.
997 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 9);
998 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
999 ASSERT_GL_NO_ERROR();
1000
1001 // Test touching the last element + 1 is invalid, using a stride.
1002 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 2, zeroOffset + 10);
1003 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1004 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1005
1006 // Test any offset is valid if no vertices are drawn.
1007 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset + 32);
1008 glDrawArraysInstanced(GL_POINTS, 0, 1, 0);
1009 ASSERT_GL_NO_ERROR();
1010}
1011
Geoff Lang407d4e72017-04-12 14:54:11 -04001012// Test that at least one attribute has a zero divisor for WebGL
1013TEST_P(WebGL2CompatibilityTest, InstancedDrawZeroDivisor)
1014{
1015 const std::string &vert =
1016 "attribute float a_pos;\n"
1017 "void main()\n"
1018 "{\n"
1019 " gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
1020 "}\n";
1021
1022 const std::string &frag =
1023 "precision highp float;\n"
1024 "void main()\n"
1025 "{\n"
1026 " gl_FragColor = vec4(1.0);\n"
1027 "}\n";
1028
1029 ANGLE_GL_PROGRAM(program, vert, frag);
1030
1031 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1032 ASSERT_NE(-1, posLocation);
1033
1034 glUseProgram(program.get());
1035
1036 GLBuffer buffer;
1037 glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
1038 glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
1039
1040 glEnableVertexAttribArray(posLocation);
1041 glVertexAttribDivisor(posLocation, 1);
1042
1043 // Test touching the last element is valid.
1044 glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, nullptr);
1045 glDrawArraysInstanced(GL_POINTS, 0, 1, 4);
1046 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1047
1048 glVertexAttribDivisor(posLocation, 0);
1049 ASSERT_GL_NO_ERROR();
1050}
1051
Corentin Wallez0844f2d2017-01-31 17:02:59 -05001052// Tests that NPOT is not enabled by default in WebGL 1 and that it can be enabled
1053TEST_P(WebGLCompatibilityTest, NPOT)
1054{
1055 EXPECT_FALSE(extensionEnabled("GL_OES_texture_npot"));
1056
1057 // Create a texture and set an NPOT mip 0, should always be acceptable.
1058 GLTexture texture;
1059 glBindTexture(GL_TEXTURE_2D, texture.get());
1060 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1061 ASSERT_GL_NO_ERROR();
1062
1063 // Try setting an NPOT mip 1 and verify the error if WebGL 1
1064 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1065 if (getClientMajorVersion() < 3)
1066 {
1067 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1068 }
1069 else
1070 {
1071 ASSERT_GL_NO_ERROR();
1072 }
1073
1074 if (extensionRequestable("GL_OES_texture_npot"))
1075 {
1076 glRequestExtensionANGLE("GL_OES_texture_npot");
1077 ASSERT_GL_NO_ERROR();
1078
1079 // Try again to set NPOT mip 1
1080 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1081 ASSERT_GL_NO_ERROR();
1082 }
1083}
1084
Jamie Madillcad97ee2017-02-02 18:52:44 -05001085template <typename T>
1086void FillTexture2D(GLuint texture,
1087 GLsizei width,
1088 GLsizei height,
1089 const T &onePixelData,
1090 GLint level,
1091 GLint internalFormat,
1092 GLenum format,
1093 GLenum type)
1094{
1095 std::vector<T> allPixelsData(width * height, onePixelData);
1096
1097 glBindTexture(GL_TEXTURE_2D, texture);
1098 glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, 0, format, type,
1099 allPixelsData.data());
1100 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1101 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1102 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1103 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1104}
1105
Frank Henigman875bbba2017-02-08 16:38:17 -05001106// Test that unset gl_Position defaults to (0,0,0,0).
1107TEST_P(WebGLCompatibilityTest, DefaultPosition)
1108{
1109 // Draw a quad where each vertex is red if gl_Position is (0,0,0,0) before it is set,
1110 // and green otherwise. The center of each quadrant will be red if and only if all
1111 // four corners are red.
1112 const std::string vertexShader =
1113 "attribute vec3 pos;\n"
1114 "varying vec4 color;\n"
1115 "void main() {\n"
1116 " if (gl_Position == vec4(0,0,0,0)) {\n"
1117 " color = vec4(1,0,0,1);\n"
1118 " } else {\n"
1119 " color = vec4(0,1,0,1);\n"
1120 " }\n"
1121 " gl_Position = vec4(pos,1);\n"
1122 "}\n";
1123
1124 const std::string fragmentShader =
1125 "precision mediump float;\n"
1126 "varying vec4 color;\n"
1127 "void main() {\n"
1128 " gl_FragColor = color;\n"
1129 "}\n";
1130
1131 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1132 drawQuad(program.get(), "pos", 0.0f, 1.0f, true);
1133 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 1 / 4, GLColor::red);
1134 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 1 / 4, getWindowHeight() * 3 / 4, GLColor::red);
1135 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 1 / 4, GLColor::red);
1136 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() * 3 / 4, GLColor::red);
1137}
1138
Jamie Madilla4595b82017-01-11 17:36:34 -05001139// Tests that a rendering feedback loop triggers a GL error under WebGL.
1140// Based on WebGL test conformance/renderbuffers/feedback-loop.html.
1141TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
1142{
1143 const std::string vertexShader =
1144 "attribute vec4 a_position;\n"
1145 "varying vec2 v_texCoord;\n"
1146 "void main() {\n"
1147 " gl_Position = a_position;\n"
1148 " v_texCoord = (a_position.xy * 0.5) + 0.5;\n"
1149 "}\n";
1150
1151 const std::string fragmentShader =
1152 "precision mediump float;\n"
1153 "varying vec2 v_texCoord;\n"
1154 "uniform sampler2D u_texture;\n"
1155 "void main() {\n"
1156 " // Shader swizzles color channels so we can tell if the draw succeeded.\n"
1157 " gl_FragColor = texture2D(u_texture, v_texCoord).gbra;\n"
1158 "}\n";
1159
1160 GLTexture texture;
Jamie Madillcad97ee2017-02-02 18:52:44 -05001161 FillTexture2D(texture.get(), 1, 1, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
Jamie Madilla4595b82017-01-11 17:36:34 -05001162
1163 ASSERT_GL_NO_ERROR();
1164
1165 GLFramebuffer framebuffer;
1166 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1167 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
1168
1169 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1170
1171 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1172
1173 GLint uniformLoc = glGetUniformLocation(program.get(), "u_texture");
1174 ASSERT_NE(-1, uniformLoc);
1175
1176 glUseProgram(program.get());
1177 glUniform1i(uniformLoc, 0);
1178 glDisable(GL_BLEND);
1179 glDisable(GL_DEPTH_TEST);
1180 ASSERT_GL_NO_ERROR();
1181
1182 // Drawing with a texture that is also bound to the current framebuffer should fail
1183 glBindTexture(GL_TEXTURE_2D, texture.get());
1184 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1185 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1186
1187 // Ensure that the texture contents did not change after the previous render
1188 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1189 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1190 ASSERT_GL_NO_ERROR();
1191 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
1192
1193 // Drawing when texture is bound to an inactive uniform should succeed
1194 GLTexture texture2;
Jamie Madillcad97ee2017-02-02 18:52:44 -05001195 FillTexture2D(texture2.get(), 1, 1, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
Jamie Madilla4595b82017-01-11 17:36:34 -05001196
1197 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1198 glActiveTexture(GL_TEXTURE1);
1199 glBindTexture(GL_TEXTURE_2D, texture.get());
1200 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1201 ASSERT_GL_NO_ERROR();
1202 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1203}
1204
Bryan Bernhart58806562017-01-05 13:09:31 -08001205// Test for the max draw buffers and color attachments.
1206TEST_P(WebGLCompatibilityTest, MaxDrawBuffersAttachmentPoints)
1207{
1208 // This test only applies to ES2.
1209 if (getClientMajorVersion() != 2)
1210 {
1211 return;
1212 }
1213
1214 GLFramebuffer fbo[2];
1215 glBindFramebuffer(GL_FRAMEBUFFER, fbo[0].get());
1216
1217 // Test that is valid when we bind with a single attachment point.
1218 GLTexture texture;
1219 glBindTexture(GL_TEXTURE_2D, texture.get());
1220 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1221 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
1222 ASSERT_GL_NO_ERROR();
1223
1224 // Test that enabling the draw buffers extension will allow us to bind with a non-zero
1225 // attachment point.
1226 if (extensionRequestable("GL_EXT_draw_buffers"))
1227 {
1228 glRequestExtensionANGLE("GL_EXT_draw_buffers");
1229 EXPECT_GL_NO_ERROR();
1230 EXPECT_TRUE(extensionEnabled("GL_EXT_draw_buffers"));
1231
1232 glBindFramebuffer(GL_FRAMEBUFFER, fbo[1].get());
1233
1234 GLTexture texture2;
1235 glBindTexture(GL_TEXTURE_2D, texture2.get());
1236 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1237 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texture2.get(),
1238 0);
1239 ASSERT_GL_NO_ERROR();
1240 }
1241}
1242
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05001243// Test that the offset in the index buffer is forced to be a multiple of the element size
1244TEST_P(WebGLCompatibilityTest, DrawElementsOffsetRestriction)
1245{
1246 const std::string &vert =
1247 "attribute vec3 a_pos;\n"
1248 "void main()\n"
1249 "{\n"
1250 " gl_Position = vec4(a_pos, 1.0);\n"
1251 "}\n";
1252
1253 const std::string &frag =
1254 "precision highp float;\n"
1255 "void main()\n"
1256 "{\n"
1257 " gl_FragColor = vec4(1.0);\n"
1258 "}\n";
1259
1260 ANGLE_GL_PROGRAM(program, vert, frag);
1261
1262 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
1263 ASSERT_NE(-1, posLocation);
1264 glUseProgram(program.get());
1265
1266 const auto &vertices = GetQuadVertices();
1267
1268 GLBuffer vertexBuffer;
1269 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
1270 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
1271 GL_STATIC_DRAW);
1272
1273 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
1274 glEnableVertexAttribArray(posLocation);
1275
1276 GLBuffer indexBuffer;
1277 const GLubyte indices[] = {0, 0, 0, 0, 0, 0, 0};
1278 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
1279 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
1280
1281 ASSERT_GL_NO_ERROR();
1282
1283 const char *zeroIndices = nullptr;
1284
1285 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, zeroIndices);
1286 ASSERT_GL_NO_ERROR();
1287
1288 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, zeroIndices);
1289 ASSERT_GL_NO_ERROR();
1290
1291 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, zeroIndices + 1);
1292 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1293}
1294
1295// Test that the offset and stride in the vertex buffer is forced to be a multiple of the element
1296// size
1297TEST_P(WebGLCompatibilityTest, VertexAttribPointerOffsetRestriction)
1298{
1299 const char *zeroOffset = nullptr;
1300
1301 // Base case, vector of two floats
1302 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset);
1303 ASSERT_GL_NO_ERROR();
1304
1305 // Test setting a non-multiple offset
1306 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 1);
1307 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1308 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 2);
1309 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1310 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, zeroOffset + 3);
1311 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1312
1313 // Test setting a non-multiple stride
1314 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 1, zeroOffset);
1315 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1316 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2, zeroOffset);
1317 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1318 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 3, zeroOffset);
1319 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1320}
1321
Jamie Madillcad97ee2017-02-02 18:52:44 -05001322void WebGLCompatibilityTest::drawBuffersEXTFeedbackLoop(GLuint program,
1323 const std::array<GLenum, 2> &drawBuffers,
1324 GLenum expectedError)
1325{
1326 glDrawBuffersEXT(2, drawBuffers.data());
1327
1328 // Make sure framebuffer is complete before feedback loop detection
1329 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1330
1331 drawQuad(program, "aPosition", 0.5f, 1.0f, true);
1332
1333 // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
1334 // it should be NO_ERROR"
1335 EXPECT_GL_ERROR(expectedError);
1336}
1337
1338// This tests that rendering feedback loops works as expected with GL_EXT_draw_buffers.
1339// Based on WebGL test conformance/extensions/webgl-draw-buffers-feedback-loop.html
1340TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoopWithDrawBuffersEXT)
1341{
1342 const std::string vertexShader =
1343 "attribute vec4 aPosition;\n"
1344 "varying vec2 texCoord;\n"
1345 "void main() {\n"
1346 " gl_Position = aPosition;\n"
1347 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
1348 "}\n";
1349
1350 const std::string fragmentShader =
1351 "#extension GL_EXT_draw_buffers : require\n"
1352 "precision mediump float;\n"
1353 "uniform sampler2D tex;\n"
1354 "varying vec2 texCoord;\n"
1355 "void main() {\n"
1356 " gl_FragData[0] = texture2D(tex, texCoord);\n"
1357 " gl_FragData[1] = texture2D(tex, texCoord);\n"
1358 "}\n";
1359
1360 GLsizei width = 8;
1361 GLsizei height = 8;
1362
1363 // This shader cannot be run in ES3, because WebGL 2 does not expose the draw buffers
1364 // extension and gl_FragData semantics are changed to enforce indexing by zero always.
1365 // TODO(jmadill): This extension should be disabled in WebGL 2 contexts.
1366 if (/*!extensionEnabled("GL_EXT_draw_buffers")*/ getClientMajorVersion() != 2)
1367 {
1368 // No WEBGL_draw_buffers support -- this is legal.
1369 return;
1370 }
1371
1372 GLint maxDrawBuffers = 0;
1373 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
1374
1375 if (maxDrawBuffers < 2)
1376 {
1377 std::cout << "Test skipped because MAX_DRAW_BUFFERS is too small." << std::endl;
1378 return;
1379 }
1380
1381 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
1382 glUseProgram(program.get());
1383 glViewport(0, 0, width, height);
1384
1385 GLTexture tex0;
1386 GLTexture tex1;
1387 GLFramebuffer fbo;
1388 FillTexture2D(tex0.get(), width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
1389 FillTexture2D(tex1.get(), width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
1390 ASSERT_GL_NO_ERROR();
1391
1392 glBindTexture(GL_TEXTURE_2D, tex1.get());
1393 GLint texLoc = glGetUniformLocation(program.get(), "tex");
1394 ASSERT_NE(-1, texLoc);
1395 glUniform1i(texLoc, 0);
1396 ASSERT_GL_NO_ERROR();
1397
1398 // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
1399 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
1400 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
1401 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1.get(), 0);
1402
1403 drawBuffersEXTFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}},
1404 GL_INVALID_OPERATION);
1405 drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
1406 GL_INVALID_OPERATION);
1407 drawBuffersEXTFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_NO_ERROR);
1408}
1409
Jamie Madill07be8bf2017-02-02 19:59:57 -05001410// Test tests that texture copying feedback loops are properly rejected in WebGL.
1411// Based on the WebGL test conformance/textures/misc/texture-copying-feedback-loops.html
1412TEST_P(WebGLCompatibilityTest, TextureCopyingFeedbackLoops)
1413{
1414 GLTexture texture;
1415 glBindTexture(GL_TEXTURE_2D, texture.get());
1416 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1417 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1418 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1419 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1420 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1421
1422 GLTexture texture2;
1423 glBindTexture(GL_TEXTURE_2D, texture2.get());
1424 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1425 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1426 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1427 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1428 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1429
1430 GLFramebuffer framebuffer;
1431 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1432 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
1433
1434 // framebuffer should be FRAMEBUFFER_COMPLETE.
1435 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1436 ASSERT_GL_NO_ERROR();
1437
1438 // testing copyTexImage2D
1439
1440 // copyTexImage2D to same texture but different level
1441 glBindTexture(GL_TEXTURE_2D, texture.get());
1442 glCopyTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 0, 0, 2, 2, 0);
1443 EXPECT_GL_NO_ERROR();
1444
1445 // copyTexImage2D to same texture same level, invalid feedback loop
1446 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
1447 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1448
1449 // copyTexImage2D to different texture
1450 glBindTexture(GL_TEXTURE_2D, texture2.get());
1451 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 2, 2, 0);
1452 EXPECT_GL_NO_ERROR();
1453
1454 // testing copyTexSubImage2D
1455
1456 // copyTexSubImage2D to same texture but different level
1457 glBindTexture(GL_TEXTURE_2D, texture.get());
1458 glCopyTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
1459 EXPECT_GL_NO_ERROR();
1460
1461 // copyTexSubImage2D to same texture same level, invalid feedback loop
1462 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
1463 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1464
1465 // copyTexSubImage2D to different texture
1466 glBindTexture(GL_TEXTURE_2D, texture2.get());
1467 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
1468 EXPECT_GL_NO_ERROR();
1469}
1470
1471void WebGLCompatibilityTest::drawBuffersFeedbackLoop(GLuint program,
1472 const std::array<GLenum, 2> &drawBuffers,
1473 GLenum expectedError)
1474{
1475 glDrawBuffers(2, drawBuffers.data());
1476
1477 // Make sure framebuffer is complete before feedback loop detection
1478 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1479
1480 drawQuad(program, "aPosition", 0.5f, 1.0f, true);
1481
1482 // "Rendering to a texture where it samples from should geneates INVALID_OPERATION. Otherwise,
1483 // it should be NO_ERROR"
1484 EXPECT_GL_ERROR(expectedError);
1485}
1486
Yuly Novikov817232e2017-02-22 18:36:10 -05001487// Tests invariance matching rules between built in varyings.
1488// Based on WebGL test conformance/glsl/misc/shaders-with-invariance.html.
1489TEST_P(WebGLCompatibilityTest, BuiltInInvariant)
1490{
1491 const std::string vertexShaderVariant =
1492 "varying vec4 v_varying;\n"
1493 "void main()\n"
1494 "{\n"
1495 " gl_PointSize = 1.0;\n"
1496 " gl_Position = v_varying;\n"
1497 "}";
1498 const std::string fragmentShaderInvariantGlFragCoord =
1499 "invariant gl_FragCoord;\n"
1500 "void main()\n"
1501 "{\n"
1502 " gl_FragColor = gl_FragCoord;\n"
1503 "}";
1504 const std::string fragmentShaderInvariantGlPointCoord =
1505 "invariant gl_PointCoord;\n"
1506 "void main()\n"
1507 "{\n"
1508 " gl_FragColor = vec4(gl_PointCoord, 0.0, 0.0);\n"
1509 "}";
1510
1511 GLuint program = CompileProgram(vertexShaderVariant, fragmentShaderInvariantGlFragCoord);
1512 EXPECT_EQ(0u, program);
1513
1514 program = CompileProgram(vertexShaderVariant, fragmentShaderInvariantGlPointCoord);
1515 EXPECT_EQ(0u, program);
1516}
1517
Geoff Lang966c9402017-04-18 12:38:27 -04001518// Test dimension and image size validation of compressed textures
1519TEST_P(WebGLCompatibilityTest, CompressedTextureS3TC)
1520{
1521 if (extensionRequestable("GL_EXT_texture_compression_dxt1"))
1522 {
1523 glRequestExtensionANGLE("GL_EXT_texture_compression_dxt1");
1524 }
1525
1526 if (!extensionEnabled("GL_EXT_texture_compression_dxt1"))
1527 {
1528 std::cout << "Test skipped because GL_EXT_texture_compression_dxt1 is not available."
1529 << std::endl;
1530 return;
1531 }
1532
1533 constexpr uint8_t CompressedImageDXT1[] = {0x00, 0xf8, 0x00, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa};
1534
1535 GLTexture texture;
1536 glBindTexture(GL_TEXTURE_2D, texture);
1537
1538 // Regular case, verify that it works
1539 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
1540 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1541 ASSERT_GL_NO_ERROR();
1542
1543 // Test various dimensions that are not valid
1544 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 3, 4, 0,
1545 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1546 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1547
1548 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 3, 0,
1549 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1550 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1551
1552 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
1553 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1554 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1555
1556 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
1557 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1558 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1559
1560 // Test various image sizes that are not valid
1561 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
1562 sizeof(CompressedImageDXT1) - 1, CompressedImageDXT1);
1563 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1564
1565 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
1566 sizeof(CompressedImageDXT1) + 1, CompressedImageDXT1);
1567 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1568
1569 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, 0,
1570 CompressedImageDXT1);
1571 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1572
1573 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 0, 0, 0,
1574 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1575 ASSERT_GL_ERROR(GL_INVALID_VALUE);
1576
1577 // Fill a full mip chain and verify that it works
1578 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
1579 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1580 glCompressedTexImage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 2, 2, 0,
1581 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1582 glCompressedTexImage2D(GL_TEXTURE_2D, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 1, 1, 0,
1583 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1584 ASSERT_GL_NO_ERROR();
1585
1586 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
1587 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1588 ASSERT_GL_NO_ERROR();
1589
1590 // Test that non-block size sub-uploads are not valid for the 0 mip
1591 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
1592 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1593 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1594
1595 // Test that non-block size sub-uploads are valid for if they fill the whole mip
1596 glCompressedTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 2, 2, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
1597 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1598 glCompressedTexSubImage2D(GL_TEXTURE_2D, 2, 0, 0, 1, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
1599 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1600 ASSERT_GL_NO_ERROR();
1601
1602 // Test that if the format miss-matches the texture, an error is generated
1603 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 2, 2, 2, 2, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
1604 sizeof(CompressedImageDXT1), CompressedImageDXT1);
1605 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
1606}
1607
Geoff Lang677bb6f2017-04-05 12:40:40 -04001608TEST_P(WebGLCompatibilityTest, L32FTextures)
1609{
1610 constexpr float textureData[] = {15.1f, 0.0f, 0.0f, 0.0f};
1611 constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0], 1.0f};
1612
1613 for (auto extension : FloatingPointTextureExtensions)
1614 {
1615 if (strlen(extension) > 0 && extensionRequestable(extension))
1616 {
1617 glRequestExtensionANGLE(extension);
1618 ASSERT_GL_NO_ERROR();
1619 }
1620
1621 // Unsized L 32F
1622 {
1623 bool texture = extensionEnabled("GL_OES_texture_float");
1624 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1625 bool render = false;
1626 TestFloatTextureFormat(GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT, texture, filter, render,
1627 textureData, readPixelData);
1628 }
1629
1630 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1631 {
1632 // Sized L 32F
1633 bool texture = extensionEnabled("GL_OES_texture_float") &&
1634 extensionEnabled("GL_EXT_texture_storage");
1635 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1636 bool render = false;
1637 TestFloatTextureFormat(GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT, texture, filter,
1638 render, textureData, readPixelData);
1639 }
1640 }
1641}
1642
1643TEST_P(WebGLCompatibilityTest, A32FTextures)
1644{
1645 constexpr float textureData[] = {33.33f, 0.0f, 0.0f, 0.0f};
1646 constexpr float readPixelData[] = {0.0f, 0.0f, 0.0f, textureData[0]};
1647
1648 for (auto extension : FloatingPointTextureExtensions)
1649 {
1650 if (strlen(extension) > 0 && extensionRequestable(extension))
1651 {
1652 glRequestExtensionANGLE(extension);
1653 ASSERT_GL_NO_ERROR();
1654 }
1655
1656 // Unsized A 32F
1657 {
1658 bool texture = extensionEnabled("GL_OES_texture_float");
1659 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1660 bool render = false;
1661 TestFloatTextureFormat(GL_ALPHA, GL_ALPHA, GL_FLOAT, texture, filter, render,
1662 textureData, readPixelData);
1663 }
1664
1665 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1666 {
1667 // Sized A 32F
1668 bool texture = extensionEnabled("GL_OES_texture_float") &&
1669 extensionEnabled("GL_EXT_texture_storage");
1670 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1671 bool render = false;
1672 TestFloatTextureFormat(GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT, texture, filter, render,
1673 textureData, readPixelData);
1674 }
1675 }
1676}
1677
1678TEST_P(WebGLCompatibilityTest, LA32FTextures)
1679{
1680 constexpr float textureData[] = {-0.21f, 15.1f, 0.0f, 0.0f};
1681 constexpr float readPixelData[] = {textureData[0], textureData[0], textureData[0],
1682 textureData[1]};
1683
1684 for (auto extension : FloatingPointTextureExtensions)
1685 {
1686 if (strlen(extension) > 0 && extensionRequestable(extension))
1687 {
1688 glRequestExtensionANGLE(extension);
1689 ASSERT_GL_NO_ERROR();
1690 }
1691
1692 // Unsized LA 32F
1693 {
1694 bool texture = extensionEnabled("GL_OES_texture_float");
1695 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1696 bool render = false;
1697 TestFloatTextureFormat(GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
1698 filter, render, textureData, readPixelData);
1699 }
1700
1701 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1702 {
1703 // Sized LA 32F
1704 bool texture = extensionEnabled("GL_OES_texture_float") &&
1705 extensionEnabled("GL_EXT_texture_storage");
1706 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1707 bool render = false;
1708 TestFloatTextureFormat(GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT, texture,
1709 filter, render, textureData, readPixelData);
1710 }
1711 }
1712}
1713
1714TEST_P(WebGLCompatibilityTest, R32FTextures)
1715{
1716 constexpr float data[] = {1000.0f, 0.0f, 0.0f, 1.0f};
1717
1718 for (auto extension : FloatingPointTextureExtensions)
1719 {
1720 if (strlen(extension) > 0 && extensionRequestable(extension))
1721 {
1722 glRequestExtensionANGLE(extension);
1723 ASSERT_GL_NO_ERROR();
1724 }
1725
1726 // Unsized R 32F
1727 {
1728 bool texture =
1729 extensionEnabled("GL_OES_texture_float") && extensionEnabled("GL_EXT_texture_rg");
1730 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1731 bool render = extensionEnabled("GL_EXT_color_buffer_float");
1732 TestFloatTextureFormat(GL_RED, GL_RED, GL_FLOAT, texture, filter, render, data, data);
1733 }
1734
1735 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1736 {
1737 // Sized R 32F
1738 bool texture =
1739 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
1740 extensionEnabled("GL_EXT_texture_rg") &&
1741 extensionEnabled("GL_EXT_texture_storage"));
1742 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1743 bool render = extensionEnabled("GL_EXT_color_buffer_float");
1744 TestFloatTextureFormat(GL_R32F, GL_RED, GL_FLOAT, texture, filter, render, data, data);
1745 }
1746 }
1747}
1748
1749TEST_P(WebGLCompatibilityTest, RG32FTextures)
1750{
1751 constexpr float data[] = {1000.0f, -0.001f, 0.0f, 1.0f};
1752
1753 for (auto extension : FloatingPointTextureExtensions)
1754 {
1755 if (strlen(extension) > 0 && extensionRequestable(extension))
1756 {
1757 glRequestExtensionANGLE(extension);
1758 ASSERT_GL_NO_ERROR();
1759 }
1760
1761 // Unsized RG 32F
1762 {
1763 bool texture =
1764 (extensionEnabled("GL_OES_texture_float") && extensionEnabled("GL_EXT_texture_rg"));
1765 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1766 bool render = extensionEnabled("GL_EXT_color_buffer_float");
1767 TestFloatTextureFormat(GL_RG, GL_RG, GL_FLOAT, texture, filter, render, data, data);
1768 }
1769
1770 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1771 {
1772 // Sized RG 32F
1773 bool texture =
1774 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
1775 extensionEnabled("GL_EXT_texture_rg") &&
1776 extensionEnabled("GL_EXT_texture_storage"));
1777 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1778 bool render = extensionEnabled("GL_EXT_color_buffer_float");
1779 TestFloatTextureFormat(GL_RG32F, GL_RG, GL_FLOAT, texture, filter, render, data, data);
1780 }
1781 }
1782}
1783
1784TEST_P(WebGLCompatibilityTest, RGB32FTextures)
1785{
Geoff Lang40762ef2017-05-08 13:47:03 -04001786 if (IsLinux() && IsIntel())
1787 {
1788 std::cout << "Test skipped on Linux Intel." << std::endl;
1789 return;
1790 }
1791
Geoff Lang677bb6f2017-04-05 12:40:40 -04001792 constexpr float data[] = {1000.0f, -500.0f, 10.0f, 1.0f};
1793
1794 for (auto extension : FloatingPointTextureExtensions)
1795 {
1796 if (strlen(extension) > 0 && extensionRequestable(extension))
1797 {
1798 glRequestExtensionANGLE(extension);
1799 ASSERT_GL_NO_ERROR();
1800 }
1801
1802 // Unsized RGB 32F
1803 {
1804 bool texture = extensionEnabled("GL_OES_texture_float");
1805 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1806 bool render = extensionEnabled("GL_CHROMIUM_color_buffer_float_rgb");
1807 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_FLOAT, texture, filter, render, data, data);
1808 }
1809
1810 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1811 {
1812 // Sized RGBA 32F
1813 bool texture =
1814 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
1815 extensionEnabled("GL_EXT_texture_storage"));
1816 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1817 bool render = extensionEnabled("GL_CHROMIUM_color_buffer_float_rgb");
1818 TestFloatTextureFormat(GL_RGB32F, GL_RGB, GL_FLOAT, texture, filter, render, data,
1819 data);
1820 }
1821 }
1822}
1823
1824TEST_P(WebGLCompatibilityTest, RGBA32FTextures)
1825{
1826 constexpr float data[] = {7000.0f, 100.0f, 33.0f, -1.0f};
1827
1828 for (auto extension : FloatingPointTextureExtensions)
1829 {
1830 if (strlen(extension) > 0 && extensionRequestable(extension))
1831 {
1832 glRequestExtensionANGLE(extension);
1833 ASSERT_GL_NO_ERROR();
1834 }
1835
1836 // Unsized RGBA 32F
1837 {
1838 bool texture = extensionEnabled("GL_OES_texture_float");
1839 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1840 bool render = extensionEnabled("GL_EXT_color_buffer_float") ||
1841 extensionEnabled("GL_CHROMIUM_color_buffer_float_rgba");
1842 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_FLOAT, texture, filter, render, data, data);
1843 }
1844
1845 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1846 {
1847 // Sized RGBA 32F
1848 bool texture =
1849 (getClientMajorVersion() >= 3) || (extensionEnabled("GL_OES_texture_float") &&
1850 extensionEnabled("GL_EXT_texture_storage"));
1851 bool filter = extensionEnabled("GL_OES_texture_float_linear");
1852 bool render = extensionEnabled("GL_EXT_color_buffer_float") ||
1853 extensionEnabled("GL_CHROMIUM_color_buffer_float_rgba");
1854 TestFloatTextureFormat(GL_RGBA32F, GL_RGBA, GL_FLOAT, texture, filter, render, data,
1855 data);
1856 }
1857 }
1858}
1859
1860TEST_P(WebGLCompatibilityTest, R16FTextures)
1861{
1862 constexpr float readPixelsData[] = {-5000.0f, 0.0f, 0.0f, 1.0f};
1863 const GLushort textureData[] = {
1864 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
1865 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
1866
1867 for (auto extension : FloatingPointTextureExtensions)
1868 {
1869 if (strlen(extension) > 0 && extensionRequestable(extension))
1870 {
1871 glRequestExtensionANGLE(extension);
1872 ASSERT_GL_NO_ERROR();
1873 }
1874
1875 // Unsized R 16F (OES)
1876 {
1877 bool texture = extensionEnabled("GL_OES_texture_half_float") &&
1878 extensionEnabled("GL_EXT_texture_rg");
1879 bool filter = getClientMajorVersion() >= 3 ||
1880 extensionEnabled("GL_OES_texture_half_float_linear");
1881 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
1882 TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT_OES, texture, filter, render,
1883 textureData, readPixelsData);
1884 }
1885
1886 // Unsized R 16F
1887 {
1888 bool texture = false;
1889 bool filter = false;
1890 bool render = false;
1891 TestFloatTextureFormat(GL_RED, GL_RED, GL_HALF_FLOAT, texture, filter, render,
1892 textureData, readPixelsData);
1893 }
1894
1895 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1896 {
1897 // Sized R 16F
1898 bool texture = getClientMajorVersion() >= 3;
1899 bool filter = getClientMajorVersion() >= 3 ||
1900 extensionEnabled("GL_OES_texture_half_float_linear");
1901 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
1902 extensionEnabled("GL_EXT_color_buffer_float");
1903 TestFloatTextureFormat(GL_R16F, GL_RED, GL_HALF_FLOAT, texture, filter, render,
1904 textureData, readPixelsData);
1905 }
1906 }
1907}
1908
1909TEST_P(WebGLCompatibilityTest, RG16FTextures)
1910{
1911 constexpr float readPixelsData[] = {7108.0f, -10.0f, 0.0f, 1.0f};
1912 const GLushort textureData[] = {
1913 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
1914 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
1915
1916 for (auto extension : FloatingPointTextureExtensions)
1917 {
1918 if (strlen(extension) > 0 && extensionRequestable(extension))
1919 {
1920 glRequestExtensionANGLE(extension);
1921 ASSERT_GL_NO_ERROR();
1922 }
1923
1924 // Unsized RG 16F (OES)
1925 {
1926 bool texture = extensionEnabled("GL_OES_texture_half_float") &&
1927 extensionEnabled("GL_EXT_texture_rg");
1928 bool filter = getClientMajorVersion() >= 3 ||
1929 extensionEnabled("GL_OES_texture_half_float_linear");
1930 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") &&
1931 extensionEnabled("GL_EXT_texture_rg");
1932 TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT_OES, texture, filter, render,
1933 textureData, readPixelsData);
1934 }
1935
1936 // Unsized RG 16F
1937 {
1938 bool texture = false;
1939 bool filter = false;
1940 bool render = false;
1941 TestFloatTextureFormat(GL_RG, GL_RG, GL_HALF_FLOAT, texture, filter, render,
1942 textureData, readPixelsData);
1943 }
1944
1945 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
1946 {
1947 // Sized RG 16F
1948 bool texture = getClientMajorVersion() >= 3;
1949 bool filter = getClientMajorVersion() >= 3 ||
1950 extensionEnabled("GL_OES_texture_half_float_linear");
1951 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
1952 extensionEnabled("GL_EXT_color_buffer_float");
1953 TestFloatTextureFormat(GL_RG16F, GL_RG, GL_HALF_FLOAT, texture, filter, render,
1954 textureData, readPixelsData);
1955 }
1956 }
1957}
1958
1959TEST_P(WebGLCompatibilityTest, RGB16FTextures)
1960{
Geoff Lang40762ef2017-05-08 13:47:03 -04001961 if (IsOzone() && IsIntel())
1962 {
1963 std::cout << "Test skipped on Intel Ozone." << std::endl;
1964 return;
1965 }
1966
Geoff Lang677bb6f2017-04-05 12:40:40 -04001967 constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, 1.0f};
1968 const GLushort textureData[] = {
1969 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
1970 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
1971
1972 for (auto extension : FloatingPointTextureExtensions)
1973 {
1974 if (strlen(extension) > 0 && extensionRequestable(extension))
1975 {
1976 glRequestExtensionANGLE(extension);
1977 ASSERT_GL_NO_ERROR();
1978 }
1979
1980 // Unsized RGB 16F (OES)
1981 {
1982 bool texture = extensionEnabled("GL_OES_texture_half_float");
1983 bool filter = getClientMajorVersion() >= 3 ||
1984 extensionEnabled("GL_OES_texture_half_float_linear");
1985 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
1986 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT_OES, texture, filter, render,
1987 textureData, readPixelsData);
1988 }
1989
1990 // Unsized RGB 16F
1991 {
1992 bool texture = false;
1993 bool filter = false;
1994 bool render = false;
1995 TestFloatTextureFormat(GL_RGB, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
1996 textureData, readPixelsData);
1997 }
1998
1999 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2000 {
2001 // Sized RGB 16F
2002 bool texture = getClientMajorVersion() >= 3;
2003 bool filter = getClientMajorVersion() >= 3 ||
2004 extensionEnabled("GL_OES_texture_half_float_linear");
2005 bool render = extensionEnabled("GL_EXT_color_buffer_half_float");
2006 TestFloatTextureFormat(GL_RGB16F, GL_RGB, GL_HALF_FLOAT, texture, filter, render,
2007 textureData, readPixelsData);
2008 }
2009 }
2010}
2011
2012TEST_P(WebGLCompatibilityTest, RGBA16FTextures)
2013{
Geoff Lang40762ef2017-05-08 13:47:03 -04002014 if (IsOzone() && IsIntel())
2015 {
2016 std::cout << "Test skipped on Intel Ozone." << std::endl;
2017 return;
2018 }
2019
Geoff Lang677bb6f2017-04-05 12:40:40 -04002020 constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, -1.0f};
2021 const GLushort textureData[] = {
2022 gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
2023 gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
2024
2025 for (auto extension : FloatingPointTextureExtensions)
2026 {
2027 if (strlen(extension) > 0 && extensionRequestable(extension))
2028 {
2029 glRequestExtensionANGLE(extension);
2030 ASSERT_GL_NO_ERROR();
2031 }
2032
2033 // Unsized RGBA 16F (OES)
2034 {
2035 bool texture = extensionEnabled("GL_OES_texture_half_float");
2036 bool filter = getClientMajorVersion() >= 3 ||
2037 extensionEnabled("GL_OES_texture_half_float_linear");
2038 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2039 extensionEnabled("GL_EXT_color_buffer_float");
2040 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES, texture, filter, render,
2041 textureData, readPixelsData);
2042 }
2043
2044 // Unsized RGBA 16F
2045 {
2046 bool texture = false;
2047 bool filter = false;
2048 bool render = false;
2049 TestFloatTextureFormat(GL_RGBA, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
2050 textureData, readPixelsData);
2051 }
2052
2053 if (getClientMajorVersion() >= 3 || extensionEnabled("GL_EXT_texture_storage"))
2054 {
2055 // Sized RGBA 16F
2056 bool texture = getClientMajorVersion() >= 3;
2057 bool filter = getClientMajorVersion() >= 3 ||
2058 extensionEnabled("GL_OES_texture_half_float_linear");
2059 bool render = extensionEnabled("GL_EXT_color_buffer_half_float") ||
2060 extensionEnabled("GL_EXT_color_buffer_float");
2061 TestFloatTextureFormat(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, texture, filter, render,
2062 textureData, readPixelsData);
2063 }
2064 }
2065}
2066
Geoff Lang6e898aa2017-06-02 11:17:26 -04002067// Test that when GL_CHROMIUM_color_buffer_float_rgb[a] is enabled, sized GL_RGB[A]_32F formats are
2068// accepted by glTexImage2D
2069TEST_P(WebGLCompatibilityTest, SizedRGBA32FFormats)
2070{
2071 if (getClientMajorVersion() != 2)
2072 {
2073 std::cout << "Test skipped because it is only valid for WebGL1 contexts." << std::endl;
2074 return;
2075 }
2076
2077 if (!extensionRequestable("GL_OES_texture_float"))
2078 {
2079 std::cout << "Test skipped because GL_OES_texture_float is not requestable." << std::endl;
2080 return;
2081 }
2082 glRequestExtensionANGLE("GL_OES_texture_float");
2083 ASSERT_GL_NO_ERROR();
2084
2085 GLTexture texture;
2086 glBindTexture(GL_TEXTURE_2D, texture);
2087
2088 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2089 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2090
2091 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
2092 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2093
2094 if (extensionRequestable("GL_CHROMIUM_color_buffer_float_rgba"))
2095 {
2096 glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgba");
2097 ASSERT_GL_NO_ERROR();
2098
2099 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2100 EXPECT_GL_NO_ERROR();
2101 }
2102
2103 if (extensionRequestable("GL_CHROMIUM_color_buffer_float_rgb"))
2104 {
2105 glRequestExtensionANGLE("GL_CHROMIUM_color_buffer_float_rgb");
2106 ASSERT_GL_NO_ERROR();
2107
2108 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, nullptr);
2109 EXPECT_GL_NO_ERROR();
2110 }
2111}
2112
Jamie Madill07be8bf2017-02-02 19:59:57 -05002113// This tests that rendering feedback loops works as expected with WebGL 2.
2114// Based on WebGL test conformance2/rendering/rendering-sampling-feedback-loop.html
2115TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDrawBuffers)
2116{
2117 const std::string vertexShader =
2118 "#version 300 es\n"
2119 "in vec4 aPosition;\n"
2120 "out vec2 texCoord;\n"
2121 "void main() {\n"
2122 " gl_Position = aPosition;\n"
2123 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
2124 "}\n";
2125
2126 const std::string fragmentShader =
2127 "#version 300 es\n"
2128 "precision mediump float;\n"
2129 "uniform sampler2D tex;\n"
2130 "in vec2 texCoord;\n"
2131 "out vec4 oColor;\n"
2132 "void main() {\n"
2133 " oColor = texture(tex, texCoord);\n"
2134 "}\n";
2135
2136 GLsizei width = 8;
2137 GLsizei height = 8;
2138
2139 GLint maxDrawBuffers = 0;
2140 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
2141 // ES3 requires a minimum value of 4 for MAX_DRAW_BUFFERS.
2142 ASSERT_GE(maxDrawBuffers, 2);
2143
2144 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2145 glUseProgram(program.get());
2146 glViewport(0, 0, width, height);
2147
2148 GLTexture tex0;
2149 GLTexture tex1;
2150 GLFramebuffer fbo;
2151 FillTexture2D(tex0.get(), width, height, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2152 FillTexture2D(tex1.get(), width, height, GLColor::green, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2153 ASSERT_GL_NO_ERROR();
2154
2155 glBindTexture(GL_TEXTURE_2D, tex1.get());
2156 GLint texLoc = glGetUniformLocation(program.get(), "tex");
2157 ASSERT_NE(-1, texLoc);
2158 glUniform1i(texLoc, 0);
2159
2160 // The sampling texture is bound to COLOR_ATTACHMENT1 during resource allocation
2161 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
2162 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
2163 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex1.get(), 0);
2164 ASSERT_GL_NO_ERROR();
2165
2166 drawBuffersFeedbackLoop(program.get(), {{GL_NONE, GL_COLOR_ATTACHMENT1}}, GL_INVALID_OPERATION);
2167 drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}},
2168 GL_INVALID_OPERATION);
2169 drawBuffersFeedbackLoop(program.get(), {{GL_COLOR_ATTACHMENT0, GL_NONE}}, GL_NO_ERROR);
2170}
2171
Jamie Madill1d37bc52017-02-02 19:59:58 -05002172// This test covers detection of rendering feedback loops between the FBO and a depth Texture.
2173// Based on WebGL test conformance2/rendering/depth-stencil-feedback-loop.html
2174TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDepthStencil)
2175{
2176 const std::string vertexShader =
2177 "#version 300 es\n"
2178 "in vec4 aPosition;\n"
2179 "out vec2 texCoord;\n"
2180 "void main() {\n"
2181 " gl_Position = aPosition;\n"
2182 " texCoord = (aPosition.xy * 0.5) + 0.5;\n"
2183 "}\n";
2184
2185 const std::string fragmentShader =
2186 "#version 300 es\n"
2187 "precision mediump float;\n"
2188 "uniform sampler2D tex;\n"
2189 "in vec2 texCoord;\n"
2190 "out vec4 oColor;\n"
2191 "void main() {\n"
2192 " oColor = texture(tex, texCoord);\n"
2193 "}\n";
2194
2195 GLsizei width = 8;
2196 GLsizei height = 8;
2197
2198 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2199 glUseProgram(program.get());
2200
2201 glViewport(0, 0, width, height);
2202
2203 GLint texLoc = glGetUniformLocation(program.get(), "tex");
2204 glUniform1i(texLoc, 0);
2205
2206 // Create textures and allocate storage
2207 GLTexture tex0;
2208 GLTexture tex1;
2209 GLRenderbuffer rb;
2210 FillTexture2D(tex0.get(), width, height, GLColor::black, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
2211 FillTexture2D(tex1.get(), width, height, 0x80, 0, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT,
2212 GL_UNSIGNED_INT);
2213 glBindRenderbuffer(GL_RENDERBUFFER, rb.get());
2214 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
2215 ASSERT_GL_NO_ERROR();
2216
2217 GLFramebuffer fbo;
2218 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
2219 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0.get(), 0);
2220
2221 // Test rendering and sampling feedback loop for depth buffer
2222 glBindTexture(GL_TEXTURE_2D, tex1.get());
2223 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex1.get(), 0);
2224 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2225
2226 // The same image is used as depth buffer during rendering.
2227 glEnable(GL_DEPTH_TEST);
2228 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2229 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2230
2231 // The same image is used as depth buffer. But depth mask is false.
2232 glDepthMask(GL_FALSE);
2233 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2234 EXPECT_GL_NO_ERROR();
2235
2236 // The same image is used as depth buffer. But depth test is not enabled during rendering.
2237 glDepthMask(GL_TRUE);
2238 glDisable(GL_DEPTH_TEST);
2239 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2240 EXPECT_GL_NO_ERROR();
2241
2242 // Test rendering and sampling feedback loop for stencil buffer
2243 glBindTexture(GL_RENDERBUFFER, rb.get());
2244 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
2245 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb.get());
2246 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
2247 constexpr GLint stencilClearValue = 0x40;
2248 glClearBufferiv(GL_STENCIL, 0, &stencilClearValue);
2249
2250 // The same image is used as stencil buffer during rendering.
2251 glEnable(GL_STENCIL_TEST);
2252 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2253 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2254
2255 // The same image is used as stencil buffer. But stencil mask is zero.
2256 glStencilMask(0x0);
2257 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2258 EXPECT_GL_NO_ERROR();
2259
2260 // The same image is used as stencil buffer. But stencil test is not enabled during rendering.
2261 glStencilMask(0xffff);
2262 glDisable(GL_STENCIL_TEST);
2263 drawQuad(program.get(), "aPosition", 0.5f, 1.0f, true);
2264 EXPECT_GL_NO_ERROR();
2265}
2266
Jamie Madillfd3dd432017-02-02 19:59:59 -05002267// The source and the target for CopyTexSubImage3D are the same 3D texture.
2268// But the level of the 3D texture != the level of the read attachment.
2269TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLevels)
2270{
2271 GLTexture texture;
2272 GLFramebuffer framebuffer;
2273
2274 glBindTexture(GL_TEXTURE_3D, texture.get());
2275 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2276
2277 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2278 glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2279 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 0);
2280 ASSERT_GL_NO_ERROR();
2281
2282 glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
2283 EXPECT_GL_NO_ERROR();
2284}
2285
2286// The source and the target for CopyTexSubImage3D are the same 3D texture.
2287// But the zoffset of the 3D texture != the layer of the read attachment.
2288TEST_P(WebGL2CompatibilityTest, NoTextureCopyingFeedbackLoopBetween3DLayers)
2289{
2290 GLTexture texture;
2291 GLFramebuffer framebuffer;
2292
2293 glBindTexture(GL_TEXTURE_3D, texture.get());
2294 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2295
2296 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2297 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 1);
2298 ASSERT_GL_NO_ERROR();
2299
2300 glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 2, 2);
2301 EXPECT_GL_NO_ERROR();
2302}
2303
2304// The source and the target for CopyTexSubImage3D are the same 3D texture.
2305// And the level / zoffset of the 3D texture is equal to the level / layer of the read attachment.
2306TEST_P(WebGL2CompatibilityTest, TextureCopyingFeedbackLoop3D)
2307{
2308 GLTexture texture;
2309 GLFramebuffer framebuffer;
2310
2311 glBindTexture(GL_TEXTURE_3D, texture.get());
2312 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2313
2314 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2315 glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2316 glTexImage3D(GL_TEXTURE_3D, 2, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2317 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 1, 0);
2318 ASSERT_GL_NO_ERROR();
2319
2320 glCopyTexSubImage3D(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
2321 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2322}
2323
Geoff Lang76e65652017-03-27 14:58:02 -04002324// Verify that errors are generated when there isn not a defined conversion between the clear type
2325// and the buffer type.
2326TEST_P(WebGL2CompatibilityTest, ClearBufferTypeCompatibity)
2327{
2328 if (IsD3D11())
2329 {
2330 std::cout << "Test skipped because it generates D3D11 runtime warnings." << std::endl;
2331 return;
2332 }
2333
2334 constexpr float clearFloat[] = {0.0f, 0.0f, 0.0f, 0.0f};
2335 constexpr int clearInt[] = {0, 0, 0, 0};
2336 constexpr unsigned int clearUint[] = {0, 0, 0, 0};
2337
2338 GLTexture texture;
2339 GLFramebuffer framebuffer;
2340
2341 glBindTexture(GL_TEXTURE_2D, texture.get());
2342 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
2343
2344 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
2345 ASSERT_GL_NO_ERROR();
2346
2347 // Unsigned integer buffer
2348 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32UI, 1, 1, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, nullptr);
2349 ASSERT_GL_NO_ERROR();
2350
2351 glClearBufferfv(GL_COLOR, 0, clearFloat);
2352 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2353
2354 glClearBufferiv(GL_COLOR, 0, clearInt);
2355 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2356
2357 glClearBufferuiv(GL_COLOR, 0, clearUint);
2358 EXPECT_GL_NO_ERROR();
2359
2360 glClear(GL_COLOR_BUFFER_BIT);
2361 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2362
2363 // Integer buffer
2364 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32I, 1, 1, 0, GL_RGBA_INTEGER, GL_INT, nullptr);
2365 ASSERT_GL_NO_ERROR();
2366
2367 glClearBufferfv(GL_COLOR, 0, clearFloat);
2368 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2369
2370 glClearBufferiv(GL_COLOR, 0, clearInt);
2371 EXPECT_GL_NO_ERROR();
2372
2373 glClearBufferuiv(GL_COLOR, 0, clearUint);
2374 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2375
2376 glClear(GL_COLOR_BUFFER_BIT);
2377 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2378
2379 // Float buffer
Geoff Lang677bb6f2017-04-05 12:40:40 -04002380 if (extensionRequestable("GL_EXT_color_buffer_float"))
2381 {
2382 glRequestExtensionANGLE("GL_EXT_color_buffer_float");
2383 }
Geoff Lang76e65652017-03-27 14:58:02 -04002384
Geoff Lang677bb6f2017-04-05 12:40:40 -04002385 if (extensionEnabled("GL_EXT_color_buffer_float"))
2386 {
2387 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, nullptr);
2388 ASSERT_GL_NO_ERROR();
Geoff Lang76e65652017-03-27 14:58:02 -04002389
Geoff Lang677bb6f2017-04-05 12:40:40 -04002390 glClearBufferfv(GL_COLOR, 0, clearFloat);
2391 EXPECT_GL_NO_ERROR();
Geoff Lang76e65652017-03-27 14:58:02 -04002392
Geoff Lang677bb6f2017-04-05 12:40:40 -04002393 glClearBufferiv(GL_COLOR, 0, clearInt);
2394 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Geoff Lang76e65652017-03-27 14:58:02 -04002395
Geoff Lang677bb6f2017-04-05 12:40:40 -04002396 glClearBufferuiv(GL_COLOR, 0, clearUint);
2397 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2398
2399 glClear(GL_COLOR_BUFFER_BIT);
2400 EXPECT_GL_NO_ERROR();
2401 }
Geoff Lang76e65652017-03-27 14:58:02 -04002402
2403 // Normalized uint buffer
2404 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
2405 ASSERT_GL_NO_ERROR();
2406
2407 glClearBufferfv(GL_COLOR, 0, clearFloat);
2408 EXPECT_GL_NO_ERROR();
2409
2410 glClearBufferiv(GL_COLOR, 0, clearInt);
2411 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2412
2413 glClearBufferuiv(GL_COLOR, 0, clearUint);
2414 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2415
2416 glClear(GL_COLOR_BUFFER_BIT);
2417 EXPECT_GL_NO_ERROR();
2418}
2419
Geoff Lange4915782017-04-12 15:19:07 -04002420// Verify that errors are generate when trying to blit from an image to itself
2421TEST_P(WebGL2CompatibilityTest, BlitFramebufferSameImage)
2422{
2423 GLTexture textures[2];
2424 glBindTexture(GL_TEXTURE_2D, textures[0]);
2425 glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
2426 glBindTexture(GL_TEXTURE_2D, textures[1]);
2427 glTexStorage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 4, 4);
2428
2429 GLRenderbuffer renderbuffers[2];
2430 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[0]);
2431 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
2432 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[1]);
2433 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 4, 4);
2434
2435 GLFramebuffer framebuffers[2];
2436 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[0]);
2437 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[1]);
2438
2439 ASSERT_GL_NO_ERROR();
2440
2441 // Same texture
2442 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
2443 0);
2444 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
2445 0);
2446 ASSERT_GL_NO_ERROR();
2447 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2448 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2449
2450 // Same textures but different renderbuffers
2451 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
2452 renderbuffers[0]);
2453 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
2454 renderbuffers[1]);
2455 ASSERT_GL_NO_ERROR();
2456 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
2457 ASSERT_GL_NO_ERROR();
2458 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
2459 GL_NEAREST);
2460 ASSERT_GL_NO_ERROR();
2461 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
2462 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
2463 GL_NEAREST);
2464 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2465
2466 // Same renderbuffers but different textures
2467 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0],
2468 0);
2469 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1],
2470 0);
2471 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
2472 renderbuffers[0]);
2473 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
2474 renderbuffers[0]);
2475 ASSERT_GL_NO_ERROR();
2476 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_COLOR_BUFFER_BIT, GL_NEAREST);
2477 ASSERT_GL_NO_ERROR();
2478 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
2479 GL_NEAREST);
2480 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2481 glBlitFramebuffer(0, 0, 4, 4, 0, 0, 4, 4,
2482 GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
2483 GL_NEAREST);
2484 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
2485}
2486
Geoff Lange0cff192017-05-30 13:04:56 -04002487// Verify that errors are generated when the fragment shader output doesn't match the bound color
2488// buffer types
2489TEST_P(WebGL2CompatibilityTest, FragmentShaderColorBufferTypeMissmatch)
2490{
2491 const std::string vertexShader =
2492 "#version 300 es\n"
2493 "void main() {\n"
2494 " gl_Position = vec4(0, 0, 0, 1);\n"
2495 "}\n";
2496
2497 const std::string fragmentShader =
2498 "#version 300 es\n"
2499 "precision mediump float;\n"
2500 "layout(location = 0) out vec4 floatOutput;\n"
2501 "layout(location = 1) out uvec4 uintOutput;\n"
2502 "layout(location = 2) out ivec4 intOutput;\n"
2503 "void main() {\n"
2504 " floatOutput = vec4(0, 0, 0, 1);\n"
2505 " uintOutput = uvec4(0, 0, 0, 1);\n"
2506 " intOutput = ivec4(0, 0, 0, 1);\n"
2507 "}\n";
2508
2509 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2510 glUseProgram(program.get());
2511
2512 GLuint floatLocation = glGetFragDataLocation(program, "floatOutput");
2513 GLuint uintLocation = glGetFragDataLocation(program, "uintOutput");
2514 GLuint intLocation = glGetFragDataLocation(program, "intOutput");
2515
2516 GLFramebuffer fbo;
2517 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2518
2519 GLRenderbuffer floatRenderbuffer;
2520 glBindRenderbuffer(GL_RENDERBUFFER, floatRenderbuffer);
2521 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
2522 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
2523 floatRenderbuffer);
2524
2525 GLRenderbuffer uintRenderbuffer;
2526 glBindRenderbuffer(GL_RENDERBUFFER, uintRenderbuffer);
2527 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8UI, 1, 1);
2528 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
2529 uintRenderbuffer);
2530
2531 GLRenderbuffer intRenderbuffer;
2532 glBindRenderbuffer(GL_RENDERBUFFER, intRenderbuffer);
2533 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8I, 1, 1);
2534 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
2535 intRenderbuffer);
2536
2537 ASSERT_GL_NO_ERROR();
2538
2539 GLint maxDrawBuffers = 0;
2540 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
2541 std::vector<GLenum> drawBuffers(static_cast<size_t>(maxDrawBuffers), GL_NONE);
2542 drawBuffers[floatLocation] = GL_COLOR_ATTACHMENT0 + floatLocation;
2543 drawBuffers[uintLocation] = GL_COLOR_ATTACHMENT0 + uintLocation;
2544 drawBuffers[intLocation] = GL_COLOR_ATTACHMENT0 + intLocation;
2545
2546 glDrawBuffers(maxDrawBuffers, drawBuffers.data());
2547
2548 // Check that the correct case generates no errors
2549 glDrawArrays(GL_TRIANGLES, 0, 6);
2550 EXPECT_GL_NO_ERROR();
2551
2552 // Unbind some buffers and verify that there are still no errors
2553 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
2554 0);
2555 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
2556 0);
2557 glDrawArrays(GL_TRIANGLES, 0, 6);
2558 EXPECT_GL_NO_ERROR();
2559
2560 // Swap the int and uint buffers to and verify that an error is generated
2561 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
2562 intRenderbuffer);
2563 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
2564 uintRenderbuffer);
2565 glDrawArrays(GL_TRIANGLES, 0, 6);
2566 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2567
2568 // Swap the float and uint buffers to and verify that an error is generated
2569 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uintLocation, GL_RENDERBUFFER,
2570 floatRenderbuffer);
2571 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + floatLocation, GL_RENDERBUFFER,
2572 uintRenderbuffer);
2573 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + intLocation, GL_RENDERBUFFER,
2574 intRenderbuffer);
2575 glDrawArrays(GL_TRIANGLES, 0, 6);
2576 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2577}
2578
Geoff Lang9ab5b822017-05-30 16:19:23 -04002579// Verify that errors are generated when the vertex shader intput doesn't match the bound attribute
2580// types
2581TEST_P(WebGL2CompatibilityTest, VertexShaderAttributeTypeMissmatch)
2582{
2583 const std::string vertexShader =
2584 "#version 300 es\n"
2585 "in vec4 floatInput;\n"
2586 "in uvec4 uintInput;\n"
2587 "in ivec4 intInput;\n"
2588 "void main() {\n"
2589 " gl_Position = vec4(floatInput.x, uintInput.x, intInput.x, 1);\n"
2590 "}\n";
2591
2592 const std::string fragmentShader =
2593 "#version 300 es\n"
2594 "precision mediump float;\n"
2595 "out vec4 outputColor;\n"
2596 "void main() {\n"
2597 " outputColor = vec4(0, 0, 0, 1);"
2598 "}\n";
2599
2600 ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
2601 glUseProgram(program.get());
2602
2603 GLint floatLocation = glGetAttribLocation(program, "floatInput");
2604 GLint uintLocation = glGetAttribLocation(program, "uintInput");
2605 GLint intLocation = glGetAttribLocation(program, "intInput");
2606
2607 // Default attributes are of float types
2608 glDrawArrays(GL_TRIANGLES, 0, 6);
2609 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2610
2611 // Set the default attributes to the correct types, should succeed
2612 glVertexAttribI4ui(uintLocation, 0, 0, 0, 1);
2613 glVertexAttribI4i(intLocation, 0, 0, 0, 1);
2614 glDrawArrays(GL_TRIANGLES, 0, 6);
2615 EXPECT_GL_NO_ERROR();
2616
2617 // Change the default float attribute to an integer, should fail
2618 glVertexAttribI4ui(floatLocation, 0, 0, 0, 1);
2619 glDrawArrays(GL_TRIANGLES, 0, 6);
2620 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2621
2622 // Use a buffer for some attributes
2623 GLBuffer buffer;
2624 glBindBuffer(GL_ARRAY_BUFFER, buffer);
2625 glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
2626 glEnableVertexAttribArray(floatLocation);
2627 glVertexAttribPointer(floatLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
2628 glDrawArrays(GL_TRIANGLES, 0, 6);
2629 EXPECT_GL_NO_ERROR();
2630
2631 // Use a float pointer attrib for a uint input
2632 glEnableVertexAttribArray(uintLocation);
2633 glVertexAttribPointer(uintLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
2634 glDrawArrays(GL_TRIANGLES, 0, 6);
2635 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2636
2637 // Use a uint pointer for the uint input
2638 glVertexAttribIPointer(uintLocation, 4, GL_UNSIGNED_INT, 0, nullptr);
2639 glDrawArrays(GL_TRIANGLES, 0, 6);
2640 EXPECT_GL_NO_ERROR();
2641}
2642
Corentin Walleze7557742017-06-01 13:09:57 -04002643// Tests the WebGL removal of undefined behavior when attachments aren't written to.
2644TEST_P(WebGLCompatibilityTest, DrawBuffers)
2645{
Corentin Walleze7557742017-06-01 13:09:57 -04002646 // Make sure we can use at least 4 attachments for the tests.
2647 bool useEXT = false;
2648 if (getClientMajorVersion() < 3)
2649 {
2650 if (!extensionRequestable("GL_EXT_draw_buffers"))
2651 {
2652 std::cout << "Test skipped because draw buffers are not available" << std::endl;
2653 return;
2654 }
2655
2656 glRequestExtensionANGLE("GL_EXT_draw_buffers");
2657 useEXT = true;
2658 EXPECT_GL_NO_ERROR();
2659 }
2660
2661 GLint maxDrawBuffers = 0;
2662 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
2663 if (maxDrawBuffers < 4)
2664 {
2665 std::cout << "Test skipped because MAX_DRAW_BUFFERS is too small." << std::endl;
2666 return;
2667 }
2668
2669 // Clears all the renderbuffers to red.
2670 auto ClearEverythingToRed = [](GLRenderbuffer *renderbuffers) {
2671 GLFramebuffer clearFBO;
2672 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, clearFBO);
2673
2674 glClearColor(1, 0, 0, 1);
2675 for (int i = 0; i < 4; ++i)
2676 {
2677 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
2678 renderbuffers[i]);
2679 glClear(GL_COLOR_BUFFER_BIT);
2680 }
2681 ASSERT_GL_NO_ERROR();
2682 };
2683
2684 // Checks that the renderbuffers specified by mask have the correct color
2685 auto CheckColors = [](GLRenderbuffer *renderbuffers, int mask, GLColor color) {
2686 GLFramebuffer readFBO;
2687 glBindFramebuffer(GL_READ_FRAMEBUFFER, readFBO);
2688
2689 for (int i = 0; i < 4; ++i)
2690 {
2691 if (mask & (1 << i))
2692 {
2693 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
2694 GL_RENDERBUFFER, renderbuffers[i]);
2695 EXPECT_PIXEL_COLOR_EQ(0, 0, color);
2696 }
2697 }
2698 ASSERT_GL_NO_ERROR();
2699 };
2700
2701 // Depending on whether we are using the extension or ES3, a different entrypoint must be called
2702 auto DrawBuffers = [](bool useEXT, int numBuffers, GLenum *buffers) {
2703 if (useEXT)
2704 {
2705 glDrawBuffersEXT(numBuffers, buffers);
2706 }
2707 else
2708 {
2709 glDrawBuffers(numBuffers, buffers);
2710 }
2711 };
2712
2713 // Initialized the test framebuffer
2714 GLFramebuffer drawFBO;
2715 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
2716
2717 GLRenderbuffer renderbuffers[4];
2718 for (int i = 0; i < 4; ++i)
2719 {
2720 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[i]);
2721 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
2722 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER,
2723 renderbuffers[i]);
2724 }
2725
2726 ASSERT_GL_NO_ERROR();
2727
2728 const char *vertESSL1 =
2729 "attribute vec4 a_pos;\n"
2730 "void main()\n"
2731 "{\n"
2732 " gl_Position = a_pos;\n"
2733 "}\n";
2734 const char *vertESSL3 =
2735 "#version 300 es\n"
2736 "in vec4 a_pos;\n"
2737 "void main()\n"
2738 "{\n"
2739 " gl_Position = a_pos;\n"
2740 "}\n";
2741
2742 GLenum allDrawBuffers[] = {
2743 GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3,
2744 };
2745
2746 GLenum halfDrawBuffers[] = {
2747 GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3,
2748 };
2749
2750 // Test that when using gl_FragColor, only the first attachment is written to.
2751 const char *fragESSL1 =
2752 "precision highp float;\n"
2753 "void main()\n"
2754 "{\n"
2755 " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
2756 "}\n";
2757 ANGLE_GL_PROGRAM(programESSL1, vertESSL1, fragESSL1);
2758
2759 {
2760 ClearEverythingToRed(renderbuffers);
2761
2762 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
2763 DrawBuffers(useEXT, 4, allDrawBuffers);
2764 drawQuad(programESSL1, "a_pos", 0.5, 1.0, true);
2765 ASSERT_GL_NO_ERROR();
2766
2767 CheckColors(renderbuffers, 0b0001, GLColor::green);
2768 CheckColors(renderbuffers, 0b1110, GLColor::red);
2769 }
2770
2771 // Test that when using gl_FragColor, but the first draw buffer is 0, then no attachment is
2772 // written to.
2773 {
2774 ClearEverythingToRed(renderbuffers);
2775
2776 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
2777 DrawBuffers(useEXT, 4, halfDrawBuffers);
2778 drawQuad(programESSL1, "a_pos", 0.5, 1.0, true);
2779 ASSERT_GL_NO_ERROR();
2780
2781 CheckColors(renderbuffers, 0b1111, GLColor::red);
2782 }
2783
2784 // Test what happens when rendering to a subset of the outputs. There is a behavior difference
2785 // between the extension and ES3. In the extension gl_FragData is implicitly declared as an
2786 // array of size MAX_DRAW_BUFFERS, so the WebGL spec stipulates that elements not written to
2787 // should default to 0. On the contrary, in ES3 outputs are specified one by one, so
2788 // attachments not declared in the shader should not be written to.
2789 const char *writeOddOutputsVert;
2790 const char *writeOddOutputsFrag;
2791 GLColor unwrittenColor;
2792 if (useEXT)
2793 {
2794 // In the extension, when an attachment isn't written to, it should get 0's
2795 unwrittenColor = GLColor(0, 0, 0, 0);
2796 writeOddOutputsVert = vertESSL1;
2797 writeOddOutputsFrag =
2798 "#extension GL_EXT_draw_buffers : require\n"
2799 "precision highp float;\n"
2800 "void main()\n"
2801 "{\n"
2802 " gl_FragData[1] = vec4(0.0, 1.0, 0.0, 1.0);\n"
2803 " gl_FragData[3] = vec4(0.0, 1.0, 0.0, 1.0);\n"
2804 "}\n";
2805 }
2806 else
2807 {
2808 // In ES3 if an attachment isn't declared, it shouldn't get written and should be red
2809 // because of the preceding clears.
2810 unwrittenColor = GLColor::red;
2811 writeOddOutputsVert = vertESSL3;
2812 writeOddOutputsFrag =
2813 "#version 300 es\n"
2814 "precision highp float;\n"
2815 "layout(location = 1) out vec4 output1;"
2816 "layout(location = 3) out vec4 output2;"
2817 "void main()\n"
2818 "{\n"
2819 " output1 = vec4(0.0, 1.0, 0.0, 1.0);\n"
2820 " output2 = vec4(0.0, 1.0, 0.0, 1.0);\n"
2821 "}\n";
2822 }
2823 ANGLE_GL_PROGRAM(writeOddOutputsProgram, writeOddOutputsVert, writeOddOutputsFrag);
2824
2825 // Test that attachments not written to get the "unwritten" color
2826 {
2827 ClearEverythingToRed(renderbuffers);
2828
2829 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
2830 DrawBuffers(useEXT, 4, allDrawBuffers);
2831 drawQuad(writeOddOutputsProgram, "a_pos", 0.5, 1.0, true);
2832 ASSERT_GL_NO_ERROR();
2833
2834 CheckColors(renderbuffers, 0b1010, GLColor::green);
2835 CheckColors(renderbuffers, 0b0101, unwrittenColor);
2836 }
2837
2838 // Test that attachments not written to get the "unwritten" color but that even when the
2839 // extension is used, disabled attachments are not written at all and stay red.
2840 {
2841 ClearEverythingToRed(renderbuffers);
2842
2843 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFBO);
2844 DrawBuffers(useEXT, 4, halfDrawBuffers);
2845 drawQuad(writeOddOutputsProgram, "a_pos", 0.5, 1.0, true);
2846 ASSERT_GL_NO_ERROR();
2847
2848 CheckColors(renderbuffers, 0b1000, GLColor::green);
2849 CheckColors(renderbuffers, 0b0100, unwrittenColor);
2850 CheckColors(renderbuffers, 0b0011, GLColor::red);
2851 }
2852}
2853
Frank Henigmanfccbac22017-05-28 17:29:26 -04002854// Linking should fail when corresponding vertex/fragment uniform blocks have different precision
2855// qualifiers.
2856TEST_P(WebGL2CompatibilityTest, UniformBlockPrecisionMismatch)
2857{
2858 const std::string vertexShader =
2859 "#version 300 es\n"
2860 "uniform Block { mediump vec4 val; };\n"
2861 "void main() { gl_Position = val; }\n";
2862 const std::string fragmentShader =
2863 "#version 300 es\n"
2864 "uniform Block { highp vec4 val; };\n"
2865 "out highp vec4 out_FragColor;\n"
2866 "void main() { out_FragColor = val; }\n";
2867
2868 GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
2869 ASSERT_NE(0u, vs);
2870 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
2871 ASSERT_NE(0u, fs);
2872
2873 GLuint program = glCreateProgram();
2874
2875 glAttachShader(program, vs);
2876 glDeleteShader(vs);
2877 glAttachShader(program, fs);
2878 glDeleteShader(fs);
2879
2880 glLinkProgram(program);
2881 GLint linkStatus;
2882 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
2883 ASSERT_EQ(0, linkStatus);
2884
2885 glDeleteProgram(program);
2886}
2887
Geoff Langc287ea62016-09-16 14:46:51 -04002888// Use this to select which configurations (e.g. which renderer, which GLES major version) these
2889// tests should be run against.
2890ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,
2891 ES2_D3D9(),
2892 ES2_D3D11(),
2893 ES3_D3D11(),
Geoff Langc287ea62016-09-16 14:46:51 -04002894 ES2_OPENGL(),
2895 ES3_OPENGL(),
2896 ES2_OPENGLES(),
2897 ES3_OPENGLES());
2898
Jamie Madill07be8bf2017-02-02 19:59:57 -05002899ANGLE_INSTANTIATE_TEST(WebGL2CompatibilityTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
Geoff Langc287ea62016-09-16 14:46:51 -04002900} // namespace