blob: 86f4954918802032683abad3268666684d10707b [file] [log] [blame]
Geoff Langc287ea62016-09-16 14:46:51 -04001//
2// Copyright 2015 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// WebGLCompatibilityTest.cpp : Tests of the GL_ANGLE_webgl_compatibility extension.
8
9#include "test_utils/ANGLETest.h"
10
11#include "test_utils/gl_raii.h"
12
13namespace angle
14{
15
16class WebGLCompatibilityTest : public ANGLETest
17{
18 protected:
19 WebGLCompatibilityTest()
20 {
21 setWindowWidth(128);
22 setWindowHeight(128);
23 setConfigRedBits(8);
24 setConfigGreenBits(8);
25 setConfigBlueBits(8);
26 setConfigAlphaBits(8);
27 setWebGLCompatibilityEnabled(true);
28 }
29
30 void SetUp() override
31 {
32 ANGLETest::SetUp();
Geoff Langc339c4e2016-11-29 10:37:36 -050033 glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
34 eglGetProcAddress("glRequestExtensionANGLE"));
Geoff Langc287ea62016-09-16 14:46:51 -040035 }
36
37 void TearDown() override { ANGLETest::TearDown(); }
38
Geoff Langc339c4e2016-11-29 10:37:36 -050039 PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
Geoff Langc287ea62016-09-16 14:46:51 -040040};
41
42// Context creation would fail if EGL_ANGLE_create_context_webgl_compatibility was not available so
43// the GL extension should always be present
44TEST_P(WebGLCompatibilityTest, ExtensionStringExposed)
45{
46 EXPECT_TRUE(extensionEnabled("GL_ANGLE_webgl_compatibility"));
47}
48
49// Verify that all extension entry points are available
50TEST_P(WebGLCompatibilityTest, EntryPoints)
51{
Geoff Langc339c4e2016-11-29 10:37:36 -050052 if (extensionEnabled("GL_ANGLE_request_extension"))
Geoff Langc287ea62016-09-16 14:46:51 -040053 {
Geoff Langc339c4e2016-11-29 10:37:36 -050054 EXPECT_NE(nullptr, eglGetProcAddress("glRequestExtensionANGLE"));
Geoff Langc287ea62016-09-16 14:46:51 -040055 }
56}
57
58// WebGL 1 allows GL_DEPTH_STENCIL_ATTACHMENT as a valid binding point. Make sure it is usable,
59// even in ES2 contexts.
60TEST_P(WebGLCompatibilityTest, DepthStencilBindingPoint)
61{
62 GLRenderbuffer renderbuffer;
63 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
64 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
65
66 GLFramebuffer framebuffer;
67 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
68 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
69 renderbuffer.get());
70
71 EXPECT_GL_NO_ERROR();
72}
73
74// Test that attempting to enable an extension that doesn't exist generates GL_INVALID_OPERATION
75TEST_P(WebGLCompatibilityTest, EnableExtensionValidation)
76{
Geoff Langc339c4e2016-11-29 10:37:36 -050077 glRequestExtensionANGLE("invalid_extension_string");
Geoff Langc287ea62016-09-16 14:46:51 -040078 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
79}
80
81// Test enabling the GL_OES_element_index_uint extension
82TEST_P(WebGLCompatibilityTest, EnableExtensionUintIndices)
83{
84 if (getClientMajorVersion() != 2)
85 {
86 // This test only works on ES2 where uint indices are not available by default
87 return;
88 }
89
90 EXPECT_FALSE(extensionEnabled("GL_OES_element_index_uint"));
91
92 GLBuffer indexBuffer;
93 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
94
95 GLuint data[] = {0, 1, 2, 1, 3, 2};
96 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
97
98 ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
99 "void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
100 glUseProgram(program.get());
101
102 glDrawElements(GL_TRIANGLES, 2, GL_UNSIGNED_INT, nullptr);
103 EXPECT_GL_ERROR(GL_INVALID_ENUM);
104
Geoff Langc339c4e2016-11-29 10:37:36 -0500105 if (extensionRequestable("GL_OES_element_index_uint"))
Geoff Langc287ea62016-09-16 14:46:51 -0400106 {
Geoff Langc339c4e2016-11-29 10:37:36 -0500107 glRequestExtensionANGLE("GL_OES_element_index_uint");
Geoff Langc287ea62016-09-16 14:46:51 -0400108 EXPECT_GL_NO_ERROR();
109 EXPECT_TRUE(extensionEnabled("GL_OES_element_index_uint"));
110
111 glDrawElements(GL_TRIANGLES, 2, GL_UNSIGNED_INT, nullptr);
112 EXPECT_GL_NO_ERROR();
113 }
114}
115
Bryan Bernhart87c182e2016-11-02 11:23:22 -0700116// Verify that shaders are of a compatible spec when the extension is enabled.
117TEST_P(WebGLCompatibilityTest, ExtensionCompilerSpec)
118{
119 EXPECT_TRUE(extensionEnabled("GL_ANGLE_webgl_compatibility"));
120
121 // Use of reserved _webgl prefix should fail when the shader specification is for WebGL.
122 const std::string &vert =
123 "struct Foo {\n"
124 " int _webgl_bar;\n"
125 "};\n"
126 "void main()\n"
127 "{\n"
128 " Foo foo = Foo(1);\n"
129 "}";
130
131 // Default fragement shader.
132 const std::string &frag =
133 "void main()\n"
134 "{\n"
135 " gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n"
136 "}";
137
138 GLuint program = CompileProgram(vert, frag);
139 EXPECT_EQ(0u, program);
140 glDeleteProgram(program);
141}
142
Corentin Wallez327411e2016-12-09 11:09:17 -0500143// Test that client-side array buffers are forbidden in WebGL mode
144TEST_P(WebGLCompatibilityTest, ForbidsClientSideArrayBuffer)
145{
146 const std::string &vert =
147 "attribute vec3 a_pos;\n"
148 "void main()\n"
149 "{\n"
150 " gl_Position = vec4(a_pos, 1.0);\n"
151 "}\n";
152
153 const std::string &frag =
154 "precision highp float;\n"
155 "void main()\n"
156 "{\n"
157 " gl_FragColor = vec4(1.0);\n"
158 "}\n";
159
160 ANGLE_GL_PROGRAM(program, vert, frag);
161
162 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
163 ASSERT_NE(-1, posLocation);
164 glUseProgram(program.get());
165
166 const auto &vertices = GetQuadVertices();
167 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices.data());
168 glEnableVertexAttribArray(posLocation);
169
170 ASSERT_GL_NO_ERROR();
171 glDrawArrays(GL_TRIANGLES, 0, 6);
172 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
173}
174
175// Test that client-side element array buffers are forbidden in WebGL mode
176TEST_P(WebGLCompatibilityTest, ForbidsClientSideElementBuffer)
177{
178 const std::string &vert =
179 "attribute vec3 a_pos;\n"
180 "void main()\n"
181 "{\n"
182 " gl_Position = vec4(a_pos, 1.0);\n"
183 "}\n";
184
185 const std::string &frag =
186 "precision highp float;\n"
187 "void main()\n"
188 "{\n"
189 " gl_FragColor = vec4(1.0);\n"
190 "}\n";
191
192 ANGLE_GL_PROGRAM(program, vert, frag);
193
194 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
195 ASSERT_NE(-1, posLocation);
196 glUseProgram(program.get());
197
198 const auto &vertices = GetQuadVertices();
199
200 GLBuffer vertexBuffer;
201 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
202 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
203 GL_STATIC_DRAW);
204
205 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
206 glEnableVertexAttribArray(posLocation);
207
208 const GLubyte indices[] = {0, 1, 2, 3, 4, 5};
209
210 ASSERT_GL_NO_ERROR();
211 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
212 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
213}
214
Corentin Wallezb1d0a2552016-12-19 16:15:54 -0500215// Tests the WebGL requirement of having the same stencil mask, writemask and ref for fron and back
216TEST_P(WebGLCompatibilityTest, RequiresSameStencilMaskAndRef)
217{
218 // Run the test in an FBO to make sure we have some stencil bits.
219 GLRenderbuffer renderbuffer;
220 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
221 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
222
223 GLFramebuffer framebuffer;
224 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
225 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
226 renderbuffer.get());
227
228 ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
229 "void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
230 glUseProgram(program.get());
231 ASSERT_GL_NO_ERROR();
232
233 // Having ref and mask the same for front and back is valid.
234 glStencilMask(255);
235 glStencilFunc(GL_ALWAYS, 0, 255);
236 glDrawArrays(GL_TRIANGLES, 0, 6);
237 ASSERT_GL_NO_ERROR();
238
239 // Having a different front - back write mask generates an error.
240 glStencilMaskSeparate(GL_FRONT, 1);
241 glDrawArrays(GL_TRIANGLES, 0, 6);
242 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
243
244 // Setting both write masks separately to the same value is valid.
245 glStencilMaskSeparate(GL_BACK, 1);
246 glDrawArrays(GL_TRIANGLES, 0, 6);
247 ASSERT_GL_NO_ERROR();
248
249 // Having a different stencil front - back mask generates an error
250 glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0, 1);
251 glDrawArrays(GL_TRIANGLES, 0, 6);
252 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
253
254 // Setting both masks separately to the same value is valid.
255 glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 1);
256 glDrawArrays(GL_TRIANGLES, 0, 6);
257 ASSERT_GL_NO_ERROR();
258
259 // Having a different stencil front - back reference generates an error
260 glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 255, 1);
261 glDrawArrays(GL_TRIANGLES, 0, 6);
262 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
263
264 // Setting both references separately to the same value is valid.
265 glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 255, 1);
266 glDrawArrays(GL_TRIANGLES, 0, 6);
267 ASSERT_GL_NO_ERROR();
268
269 // Using different stencil funcs, everything being equal is valid.
270 glStencilFuncSeparate(GL_BACK, GL_NEVER, 255, 1);
271 glDrawArrays(GL_TRIANGLES, 0, 6);
272 ASSERT_GL_NO_ERROR();
273}
274
Geoff Langc287ea62016-09-16 14:46:51 -0400275// Use this to select which configurations (e.g. which renderer, which GLES major version) these
276// tests should be run against.
277ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,
278 ES2_D3D9(),
279 ES2_D3D11(),
280 ES3_D3D11(),
281 ES2_D3D11_FL9_3(),
282 ES2_OPENGL(),
283 ES3_OPENGL(),
284 ES2_OPENGLES(),
285 ES3_OPENGLES());
286
287} // namespace