blob: 2c0aef153207e3cc5ad76527d59433ab3ead83c1 [file] [log] [blame]
Martin Radev14a26ae2017-07-24 15:56:29 +03001//
2// Copyright 2017 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// Multiview draw tests:
7// Test issuing multiview Draw* commands.
8//
9
10#include "test_utils/ANGLETest.h"
11#include "test_utils/gl_raii.h"
12
13using namespace angle;
14
15class MultiviewDrawTest : public ANGLETest
16{
17 protected:
18 MultiviewDrawTest()
19 {
20 setWindowWidth(128);
21 setWindowHeight(128);
22 setWebGLCompatibilityEnabled(true);
23 }
Martin Radev7cf61662017-07-26 17:10:53 +030024 virtual ~MultiviewDrawTest() {}
Martin Radev14a26ae2017-07-24 15:56:29 +030025
26 void SetUp() override
27 {
28 ANGLETest::SetUp();
29
30 glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
31 eglGetProcAddress("glRequestExtensionANGLE"));
32 }
33
34 // Requests the ANGLE_multiview extension and returns true if the operation succeeds.
35 bool requestMultiviewExtension()
36 {
37 if (extensionRequestable("GL_ANGLE_multiview"))
38 {
39 glRequestExtensionANGLE("GL_ANGLE_multiview");
40 }
41
42 if (!extensionEnabled("GL_ANGLE_multiview"))
43 {
44 std::cout << "Test skipped due to missing GL_ANGLE_multiview." << std::endl;
45 return false;
46 }
47 return true;
48 }
49
50 PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
51};
52
Martin Radev7cf61662017-07-26 17:10:53 +030053class MultiviewDrawValidationTest : public MultiviewDrawTest
54{
55 protected:
56 MultiviewDrawValidationTest() {}
57
58 void SetUp() override
59 {
60 MultiviewDrawTest::SetUp();
61
62 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
63
64 glBindTexture(GL_TEXTURE_2D, mTex2d);
65 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
66
67 glBindVertexArray(mVao);
68
69 const float kVertexData[3] = {0.0f};
70 glBindBuffer(GL_ARRAY_BUFFER, mVbo);
71 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
72
73 const unsigned int kIndices[3] = {0u, 1u, 2u};
74 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo);
75 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
76 GL_STATIC_DRAW);
77 ASSERT_GL_NO_ERROR();
78 }
79
80 GLTexture mTex2d;
81 GLVertexArray mVao;
82 GLBuffer mVbo;
83 GLBuffer mIbo;
84 GLFramebuffer mFramebuffer;
85};
86
Martin Radev14a26ae2017-07-24 15:56:29 +030087// The test verifies that glDraw*Indirect:
88// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
89// than 1.
90// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +030091TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +030092{
93 if (!requestMultiviewExtension())
94 {
95 return;
96 }
97
Martin Radev14a26ae2017-07-24 15:56:29 +030098 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +030099
100 const std::string fsSource =
101 "#version 300 es\n"
102 "#extension GL_OVR_multiview : require\n"
103 "precision mediump float;\n"
104 "void main()\n"
105 "{}\n";
106
Martin Radev14a26ae2017-07-24 15:56:29 +0300107 GLBuffer commandBuffer;
108 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
109 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
110 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
111 ASSERT_GL_NO_ERROR();
112
Martin Radev14a26ae2017-07-24 15:56:29 +0300113 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
114 {
115 const std::string &vsSource =
116 "#version 300 es\n"
117 "#extension GL_OVR_multiview : require\n"
118 "layout(num_views = 2) in;\n"
119 "void main()\n"
120 "{}\n";
121 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
122 glUseProgram(program);
123
Martin Radev7cf61662017-07-26 17:10:53 +0300124 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
125 0, 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300126
127 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
128 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
129
130 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
131 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
132 }
133
134 // Check that no errors are generated if the number of views is 1.
135 {
136 const std::string &vsSource =
137 "#version 300 es\n"
138 "#extension GL_OVR_multiview : require\n"
139 "layout(num_views = 1) in;\n"
140 "void main()\n"
141 "{}\n";
142 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
143 glUseProgram(program);
144
Martin Radev7cf61662017-07-26 17:10:53 +0300145 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
146 0, 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300147
148 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
149 EXPECT_GL_NO_ERROR();
150
151 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
152 EXPECT_GL_NO_ERROR();
153 }
154}
155
Martin Radev7cf61662017-07-26 17:10:53 +0300156// The test verifies that glDraw*:
157// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
158// program differs.
159// 2) does not generate any error if the number of views is the same.
160// 3) does not generate any error if the program does not use the multiview extension.
161TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
162{
163 if (!requestMultiviewExtension())
164 {
165 return;
166 }
167
168 const GLint viewportOffsets[4] = {0, 0, 2, 0};
169
170 const std::string &vsSource =
171 "#version 300 es\n"
172 "#extension GL_OVR_multiview : require\n"
173 "layout(num_views = 2) in;\n"
174 "void main()\n"
175 "{}\n";
176 const std::string &fsSource =
177 "#version 300 es\n"
178 "#extension GL_OVR_multiview : require\n"
179 "precision mediump float;\n"
180 "void main()\n"
181 "{}\n";
182 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
183 glUseProgram(program);
184
185 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
186 // number of views.
187 {
188 // The framebuffer has only 1 view.
189 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
190 0, 1, &viewportOffsets[0]);
191
192 glDrawArrays(GL_TRIANGLES, 0, 3);
193 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
194
195 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
196 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
197 }
198
199 // Check that no errors are generated if the number of views in both program and draw
200 // framebuffer matches.
201 {
202 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
203 0, 2, &viewportOffsets[0]);
204
205 glDrawArrays(GL_TRIANGLES, 0, 3);
206 EXPECT_GL_NO_ERROR();
207
208 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
209 EXPECT_GL_NO_ERROR();
210 }
211
212 // Check that no errors are generated if the program does not use the multiview extension.
213 {
214 const std::string &vsSourceNoMultiview =
215 "#version 300 es\n"
216 "void main()\n"
217 "{}\n";
218 const std::string &fsSourceNoMultiview =
219 "#version 300 es\n"
220 "precision mediump float;\n"
221 "void main()\n"
222 "{}\n";
223 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
224 glUseProgram(programNoMultiview);
225
226 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
227 0, 2, &viewportOffsets[0]);
228
229 glDrawArrays(GL_TRIANGLES, 0, 3);
230 EXPECT_GL_NO_ERROR();
231
232 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
233 EXPECT_GL_NO_ERROR();
234 }
235}
236
Martin Radev7e69f762017-07-27 14:54:13 +0300237// The test verifies that glDraw*:
238// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
239// greater than 1 and there is an active transform feedback object.
240// 2) does not generate any error if the number of views in the draw framebuffer is 1.
241TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
242{
243 if (!requestMultiviewExtension())
244 {
245 return;
246 }
247
248 const GLint viewportOffsets[4] = {0, 0, 2, 0};
249
250 const std::string &vsSource =
251 "#version 300 es\n"
252 "void main()\n"
253 "{}\n";
254 const std::string &fsSource =
255 "#version 300 es\n"
256 "precision mediump float;\n"
257 "void main()\n"
258 "{}\n";
259 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
260 glUseProgram(program);
261
262 GLBuffer tbo;
263 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
264 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4u, nullptr, GL_STATIC_DRAW);
265
266 GLTransformFeedback transformFeedback;
267 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
268 glBeginTransformFeedback(GL_TRIANGLES);
269 ASSERT_GL_NO_ERROR();
270
271 // Check that drawArrays generates an error when there is an active transform feedback object
272 // and the number of views in the draw framebuffer is greater than 1.
273 {
274 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
275 0, 2, &viewportOffsets[0]);
276 glDrawArrays(GL_TRIANGLES, 0, 3);
277 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
278 }
279
280 // Check that drawArrays does not generate an error when the number of views in the draw
281 // framebuffer is 1.
282 {
283 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
284 0, 1, &viewportOffsets[0]);
285 glDrawArrays(GL_TRIANGLES, 0, 3);
286 EXPECT_GL_NO_ERROR();
287 }
288
289 glEndTransformFeedback();
290}
291
Martin Radevffe754b2017-07-31 10:38:07 +0300292// The test verifies that glDraw*:
293// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
294// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
295// 2) does not generate any error if the number of views in the draw framebuffer is 1.
296TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
297{
298 if (!requestMultiviewExtension())
299 {
300 return;
301 }
302
303 if (!extensionEnabled("GL_EXT_disjoint_timer_query"))
304 {
305 std::cout << "Test skipped because GL_EXT_disjoint_timer_query is not available."
306 << std::endl;
307 return;
308 }
309
310 const GLint viewportOffsets[4] = {0, 0, 2, 0};
311 const std::string &vsSource =
312 "#version 300 es\n"
313 "void main()\n"
314 "{}\n";
315 const std::string &fsSource =
316 "#version 300 es\n"
317 "precision mediump float;\n"
318 "void main()\n"
319 "{}\n";
320 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
321 glUseProgram(program);
322
323 GLuint query = 0u;
324 glGenQueriesEXT(1, &query);
325 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
326
327 // Check first case.
328 {
329 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
330 0, 2, &viewportOffsets[0]);
331 glDrawArrays(GL_TRIANGLES, 0, 3);
332 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
333 }
334
335 // Check second case.
336 {
337 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
338 0, 1, &viewportOffsets[0]);
339 glDrawArrays(GL_TRIANGLES, 0, 3);
340 EXPECT_GL_NO_ERROR();
341 }
342
343 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
344 glDeleteQueries(1, &query);
345}
346
Martin Radev7cf61662017-07-26 17:10:53 +0300347ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest, ES31_OPENGL());