blob: 911825efb68ff1b4a1e408af29380e5a034d15cd [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
Martin Radev61bd9992017-08-11 13:10:55 +030015namespace
16{
17GLuint CreateSimplePassthroughProgram()
18{
19 const std::string vsSource =
20 "#version 300 es\n"
21 "#extension GL_OVR_multiview : require\n"
22 "layout(num_views = 2) in;\n"
23 "layout(location=0) in vec2 vPosition;\n"
24 "void main()\n"
25 "{\n"
26 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
27 "}\n";
28
29 const std::string fsSource =
30 "#version 300 es\n"
31 "#extension GL_OVR_multiview : require\n"
32 "precision mediump float;\n"
33 "out vec4 col;\n"
34 "void main()\n"
35 "{\n"
36 " col = vec4(1,0,0,1);\n"
37 "}\n";
38 return CompileProgram(vsSource, fsSource);
39}
40
41std::vector<Vector2> ConvertPixelCoordinatesToClipSpace(const std::vector<Vector2I> &pixels,
42 int width,
43 int height)
44{
45 std::vector<Vector2> result(pixels.size());
46 for (size_t i = 0; i < pixels.size(); ++i)
47 {
48 const auto &pixel = pixels[i];
49 float pixelCenterRelativeX = (static_cast<float>(pixel.x()) + .5f) / width;
50 float pixelCenterRelativeY = (static_cast<float>(pixel.y()) + .5f) / height;
51 float xInClipSpace = 2.f * pixelCenterRelativeX - 1.f;
52 float yInClipSpace = 2.f * pixelCenterRelativeY - 1.f;
53 result[i] = Vector2(xInClipSpace, yInClipSpace);
54 }
55 return result;
56}
57} // namespace
58
Martin Radev3c25ad02017-08-22 17:36:53 +030059struct MultiviewTestParams final : public PlatformParameters
60{
61 MultiviewTestParams(GLenum multiviewLayout, const EGLPlatformParameters &eglPlatformParameters)
62 : PlatformParameters(3, 0, eglPlatformParameters), mMultiviewLayout(multiviewLayout)
63 {
64 ASSERT(multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE ||
65 multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
66 }
67 GLenum mMultiviewLayout;
68};
69
70std::ostream &operator<<(std::ostream &os, const MultiviewTestParams &params)
71{
72 const PlatformParameters &base = static_cast<const PlatformParameters &>(params);
73 os << base;
74 switch (params.mMultiviewLayout)
75 {
76 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
77 os << "_layered";
78 break;
79 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
80 os << "_side_by_side";
81 break;
82 default:
83 UNREACHABLE();
84 }
85 return os;
86}
87
88class MultiviewDrawTest : public ANGLETestBase
Martin Radev14a26ae2017-07-24 15:56:29 +030089{
90 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +030091 MultiviewDrawTest(const PlatformParameters &params) : ANGLETestBase(params)
Martin Radev14a26ae2017-07-24 15:56:29 +030092 {
93 setWindowWidth(128);
94 setWindowHeight(128);
95 setWebGLCompatibilityEnabled(true);
96 }
Martin Radev7cf61662017-07-26 17:10:53 +030097 virtual ~MultiviewDrawTest() {}
Martin Radev14a26ae2017-07-24 15:56:29 +030098
Martin Radev3c25ad02017-08-22 17:36:53 +030099 void DrawTestSetUp()
Martin Radev14a26ae2017-07-24 15:56:29 +0300100 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300101 ANGLETestBase::ANGLETestSetUp();
Martin Radev14a26ae2017-07-24 15:56:29 +0300102
103 glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
104 eglGetProcAddress("glRequestExtensionANGLE"));
105 }
106
107 // Requests the ANGLE_multiview extension and returns true if the operation succeeds.
108 bool requestMultiviewExtension()
109 {
110 if (extensionRequestable("GL_ANGLE_multiview"))
111 {
112 glRequestExtensionANGLE("GL_ANGLE_multiview");
113 }
114
115 if (!extensionEnabled("GL_ANGLE_multiview"))
116 {
117 std::cout << "Test skipped due to missing GL_ANGLE_multiview." << std::endl;
118 return false;
119 }
120 return true;
121 }
122
123 PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
124};
125
Martin Radev3c25ad02017-08-22 17:36:53 +0300126class MultiviewDrawValidationTest : public MultiviewDrawTest,
127 public ::testing::TestWithParam<PlatformParameters>
Martin Radev7cf61662017-07-26 17:10:53 +0300128{
129 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300130 MultiviewDrawValidationTest() : MultiviewDrawTest(GetParam()) {}
Martin Radev7cf61662017-07-26 17:10:53 +0300131
132 void SetUp() override
133 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300134 MultiviewDrawTest::DrawTestSetUp();
Martin Radev7cf61662017-07-26 17:10:53 +0300135
136 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
137
138 glBindTexture(GL_TEXTURE_2D, mTex2d);
139 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
140
141 glBindVertexArray(mVao);
142
143 const float kVertexData[3] = {0.0f};
144 glBindBuffer(GL_ARRAY_BUFFER, mVbo);
145 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
146
147 const unsigned int kIndices[3] = {0u, 1u, 2u};
148 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo);
149 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
150 GL_STATIC_DRAW);
151 ASSERT_GL_NO_ERROR();
152 }
153
154 GLTexture mTex2d;
155 GLVertexArray mVao;
156 GLBuffer mVbo;
157 GLBuffer mIbo;
158 GLFramebuffer mFramebuffer;
159};
160
Martin Radev3c25ad02017-08-22 17:36:53 +0300161class MultiviewRenderTestBase : public MultiviewDrawTest
Martin Radev8f276e22017-05-30 12:05:52 +0300162{
163 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300164 MultiviewRenderTestBase(const PlatformParameters &params, GLenum multiviewLayout)
165 : MultiviewDrawTest(params),
166 mMultiviewLayout(multiviewLayout),
167 mViewWidth(0),
168 mViewHeight(0),
169 mNumViews(0)
Martin Radev8f276e22017-05-30 12:05:52 +0300170 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300171 }
172 void RenderTestSetUp() { MultiviewDrawTest::DrawTestSetUp(); }
173 void createFBO(int viewWidth, int height, int numViews)
174 {
175 mViewWidth = viewWidth;
176 mViewHeight = height;
177 mNumViews = numViews;
Martin Radev8f276e22017-05-30 12:05:52 +0300178
Martin Radev0abb7a22017-08-28 15:34:45 +0300179 mColorTexture.reset();
180 mDepthTexture.reset();
181 mDrawFramebuffer.reset();
182 mReadFramebuffer.clear();
183
Martin Radev8f276e22017-05-30 12:05:52 +0300184 // Create color and depth textures.
Martin Radev3c25ad02017-08-22 17:36:53 +0300185 switch (mMultiviewLayout)
Martin Radev8f276e22017-05-30 12:05:52 +0300186 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300187 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
188 {
189 int textureWidth = viewWidth * numViews;
190 glBindTexture(GL_TEXTURE_2D, mColorTexture);
191 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, height, 0, GL_RGBA,
192 GL_UNSIGNED_BYTE, NULL);
193 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
194 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
195
196 glBindTexture(GL_TEXTURE_2D, mDepthTexture);
197 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, textureWidth, height, 0,
198 GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
199 glBindTexture(GL_TEXTURE_2D, 0);
200 break;
201 }
202 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
203 glBindTexture(GL_TEXTURE_2D_ARRAY, mColorTexture);
204 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, viewWidth, height, numViews, 0,
205 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
206 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
207 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
208
209 glBindTexture(GL_TEXTURE_2D_ARRAY, mDepthTexture);
210 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, viewWidth, height,
211 numViews, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
212 glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
213 break;
214 default:
215 UNREACHABLE();
Martin Radev8f276e22017-05-30 12:05:52 +0300216 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300217 ASSERT_GL_NO_ERROR();
218
219 // Create draw framebuffer to be used for multiview rendering.
220 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
221 switch (mMultiviewLayout)
222 {
223 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
224 {
225 std::vector<GLint> viewportOffsets(numViews * 2);
226 for (int i = 0u; i < numViews; ++i)
227 {
228 viewportOffsets[i * 2] = i * viewWidth;
229 viewportOffsets[i * 2 + 1] = 0;
230 }
231 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER,
232 GL_COLOR_ATTACHMENT0, mColorTexture, 0,
233 numViews, &viewportOffsets[0]);
234 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER,
235 GL_DEPTH_ATTACHMENT, mDepthTexture, 0,
236 numViews, &viewportOffsets[0]);
237 break;
238 }
239 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
240 glFramebufferTextureMultiviewLayeredANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
241 mColorTexture, 0, 0, numViews);
242 glFramebufferTextureMultiviewLayeredANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
243 mDepthTexture, 0, 0, numViews);
244 break;
245 default:
246 UNREACHABLE();
247 }
Martin Radev8f276e22017-05-30 12:05:52 +0300248
249 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
250 glDrawBuffers(1, DrawBuffers);
251 ASSERT_GL_NO_ERROR();
252 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
253
254 // Create read framebuffer to be used to retrieve the pixel information for testing
255 // purposes.
Martin Radev3c25ad02017-08-22 17:36:53 +0300256 switch (mMultiviewLayout)
257 {
258 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
259 mReadFramebuffer.resize(1);
260 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
261 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
262 mColorTexture, 0);
263 break;
264 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
265 mReadFramebuffer.resize(numViews);
266 for (int i = 0; i < numViews; ++i)
267 {
268 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
269 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
270 mColorTexture, 0, i);
271 }
272 break;
273 default:
274 UNREACHABLE();
275 }
Martin Radev8f276e22017-05-30 12:05:52 +0300276 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
277
278 // Clear the buffers.
Martin Radev3c25ad02017-08-22 17:36:53 +0300279 glViewport(0, 0, viewWidth, height);
280 if (mMultiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
281 {
282 // Enable the scissor test only for side-by-side framebuffers.
283 glEnable(GL_SCISSOR_TEST);
284 glScissor(0, 0, viewWidth, height);
285 }
Martin Radev61bd9992017-08-11 13:10:55 +0300286 glClearColor(0, 0, 0, 1);
Martin Radev8f276e22017-05-30 12:05:52 +0300287 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev3c25ad02017-08-22 17:36:53 +0300288 }
Martin Radev8f276e22017-05-30 12:05:52 +0300289
Martin Radev3c25ad02017-08-22 17:36:53 +0300290 GLColor GetViewColor(int x, int y, int view)
291 {
292 switch (mMultiviewLayout)
293 {
294 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
295 return ReadColor(view * mViewWidth + x, y);
296 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
297 ASSERT(static_cast<size_t>(view) < mReadFramebuffer.size());
298 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
299 return ReadColor(x, y);
300 default:
301 UNREACHABLE();
302 }
303 return GLColor(0, 0, 0, 0);
Martin Radev8f276e22017-05-30 12:05:52 +0300304 }
305
306 GLTexture mColorTexture;
307 GLTexture mDepthTexture;
308 GLFramebuffer mDrawFramebuffer;
Martin Radev3c25ad02017-08-22 17:36:53 +0300309 std::vector<GLFramebuffer> mReadFramebuffer;
310 GLenum mMultiviewLayout;
311 int mViewWidth;
312 int mViewHeight;
313 int mNumViews;
Martin Radev8f276e22017-05-30 12:05:52 +0300314};
315
Martin Radev3c25ad02017-08-22 17:36:53 +0300316class MultiviewRenderTest : public MultiviewRenderTestBase,
317 public ::testing::TestWithParam<MultiviewTestParams>
Martin Radev8f276e22017-05-30 12:05:52 +0300318{
319 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300320 MultiviewRenderTest() : MultiviewRenderTestBase(GetParam(), GetParam().mMultiviewLayout) {}
321 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
322};
323
324class MultiviewRenderDualViewTest : public MultiviewRenderTest
325{
326 protected:
327 MultiviewRenderDualViewTest() : mProgram(0u) {}
328 ~MultiviewRenderDualViewTest()
Martin Radev8f276e22017-05-30 12:05:52 +0300329 {
330 if (mProgram != 0u)
331 {
332 glDeleteProgram(mProgram);
333 }
334 }
335
336 void SetUp() override
337 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300338 MultiviewRenderTest::SetUp();
Martin Radev8f276e22017-05-30 12:05:52 +0300339
340 if (!requestMultiviewExtension())
341 {
342 return;
343 }
344
345 const std::string vsSource =
346 "#version 300 es\n"
347 "#extension GL_OVR_multiview : require\n"
348 "layout(num_views = 2) in;\n"
349 "in vec4 vPosition;\n"
350 "void main()\n"
351 "{\n"
352 " gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x*0.5 + 0.5 : vPosition.x*0.5);\n"
353 " gl_Position.yzw = vPosition.yzw;\n"
354 "}\n";
355
356 const std::string fsSource =
357 "#version 300 es\n"
358 "#extension GL_OVR_multiview : require\n"
359 "precision mediump float;\n"
360 "out vec4 col;\n"
361 "void main()\n"
362 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300363 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300364 "}\n";
365
Martin Radev3c25ad02017-08-22 17:36:53 +0300366 createFBO(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +0300367 mProgram = CompileProgram(vsSource, fsSource);
368 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300369 glUseProgram(mProgram);
370 ASSERT_GL_NO_ERROR();
371 }
372
373 void checkOutput()
374 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300375 EXPECT_EQ(GLColor::black, GetViewColor(0, 0, 0));
376 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
377 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
378 EXPECT_EQ(GLColor::black, GetViewColor(1, 0, 1));
Martin Radev8f276e22017-05-30 12:05:52 +0300379 }
380
381 GLuint mProgram;
382};
383
Martin Radev3c25ad02017-08-22 17:36:53 +0300384class MultiviewOcclusionQueryTest : public MultiviewRenderTest
Martin Radev0d671c92017-08-10 16:41:52 +0300385{
386 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300387 MultiviewOcclusionQueryTest() {}
Martin Radev0d671c92017-08-10 16:41:52 +0300388
389 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
390 {
391 GLuint query;
392 glGenQueries(1, &query);
393 glBeginQuery(GL_ANY_SAMPLES_PASSED, query);
394 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
395 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
396
397 GLuint result = GL_TRUE;
398 glGetQueryObjectuiv(query, GL_QUERY_RESULT, &result);
399 return result;
400 }
401};
402
Martin Radev3c25ad02017-08-22 17:36:53 +0300403class MultiviewProgramGenerationTest : public MultiviewRenderTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300404{
405 protected:
406 MultiviewProgramGenerationTest() {}
407};
408
Martin Radev3c25ad02017-08-22 17:36:53 +0300409class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300410{
411 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300412 MultiviewRenderPrimitiveTest() {}
Martin Radev61bd9992017-08-11 13:10:55 +0300413
414 void setupGeometry(const std::vector<Vector2> &vertexData)
415 {
Martin Radev61bd9992017-08-11 13:10:55 +0300416 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
417 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
418 GL_STATIC_DRAW);
419 glEnableVertexAttribArray(0);
420 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
421 }
422
Martin Radev3c25ad02017-08-22 17:36:53 +0300423 void checkRedChannel(const GLubyte expectedRedChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300424 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300425 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300426 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300427 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300428 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300429 for (int h = 0; h < mViewHeight; ++h)
430 {
431 size_t flatIndex =
432 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
433 EXPECT_EQ(GLColor(expectedRedChannelData[flatIndex], 0, 0, 255),
434 GetViewColor(w, h, view));
435 }
Martin Radev61bd9992017-08-11 13:10:55 +0300436 }
437 }
438 }
Martin Radev61bd9992017-08-11 13:10:55 +0300439 GLBuffer mVBO;
440};
441
Martin Radev3c25ad02017-08-22 17:36:53 +0300442class MultiviewSideBySideRenderTest : public MultiviewRenderTestBase,
443 public ::testing::TestWithParam<PlatformParameters>
444{
445 protected:
446 MultiviewSideBySideRenderTest()
447 : MultiviewRenderTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
448 {
449 }
450 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
451};
452
Martin Radev14a26ae2017-07-24 15:56:29 +0300453// The test verifies that glDraw*Indirect:
454// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
455// than 1.
456// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +0300457TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300458{
459 if (!requestMultiviewExtension())
460 {
461 return;
462 }
463
Martin Radev14a26ae2017-07-24 15:56:29 +0300464 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +0300465
466 const std::string fsSource =
467 "#version 300 es\n"
468 "#extension GL_OVR_multiview : require\n"
469 "precision mediump float;\n"
470 "void main()\n"
471 "{}\n";
472
Martin Radev14a26ae2017-07-24 15:56:29 +0300473 GLBuffer commandBuffer;
474 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
475 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
476 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
477 ASSERT_GL_NO_ERROR();
478
Martin Radev14a26ae2017-07-24 15:56:29 +0300479 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
480 {
481 const std::string &vsSource =
482 "#version 300 es\n"
483 "#extension GL_OVR_multiview : require\n"
484 "layout(num_views = 2) in;\n"
485 "void main()\n"
486 "{}\n";
487 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
488 glUseProgram(program);
489
Martin Radev7cf61662017-07-26 17:10:53 +0300490 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
491 0, 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300492
493 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
494 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
495
496 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
497 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
498 }
499
500 // Check that no errors are generated if the number of views is 1.
501 {
502 const std::string &vsSource =
503 "#version 300 es\n"
504 "#extension GL_OVR_multiview : require\n"
505 "layout(num_views = 1) in;\n"
506 "void main()\n"
507 "{}\n";
508 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
509 glUseProgram(program);
510
Martin Radev7cf61662017-07-26 17:10:53 +0300511 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
512 0, 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300513
514 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
515 EXPECT_GL_NO_ERROR();
516
517 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
518 EXPECT_GL_NO_ERROR();
519 }
520}
521
Martin Radev7cf61662017-07-26 17:10:53 +0300522// The test verifies that glDraw*:
523// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
524// program differs.
525// 2) does not generate any error if the number of views is the same.
526// 3) does not generate any error if the program does not use the multiview extension.
527TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
528{
529 if (!requestMultiviewExtension())
530 {
531 return;
532 }
533
534 const GLint viewportOffsets[4] = {0, 0, 2, 0};
535
536 const std::string &vsSource =
537 "#version 300 es\n"
538 "#extension GL_OVR_multiview : require\n"
539 "layout(num_views = 2) in;\n"
540 "void main()\n"
541 "{}\n";
542 const std::string &fsSource =
543 "#version 300 es\n"
544 "#extension GL_OVR_multiview : require\n"
545 "precision mediump float;\n"
546 "void main()\n"
547 "{}\n";
548 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
549 glUseProgram(program);
550
551 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
552 // number of views.
553 {
554 // The framebuffer has only 1 view.
555 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
556 0, 1, &viewportOffsets[0]);
557
558 glDrawArrays(GL_TRIANGLES, 0, 3);
559 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
560
561 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
562 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
563 }
564
565 // Check that no errors are generated if the number of views in both program and draw
566 // framebuffer matches.
567 {
568 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
569 0, 2, &viewportOffsets[0]);
570
571 glDrawArrays(GL_TRIANGLES, 0, 3);
572 EXPECT_GL_NO_ERROR();
573
574 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
575 EXPECT_GL_NO_ERROR();
576 }
577
578 // Check that no errors are generated if the program does not use the multiview extension.
579 {
580 const std::string &vsSourceNoMultiview =
581 "#version 300 es\n"
582 "void main()\n"
583 "{}\n";
584 const std::string &fsSourceNoMultiview =
585 "#version 300 es\n"
586 "precision mediump float;\n"
587 "void main()\n"
588 "{}\n";
589 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
590 glUseProgram(programNoMultiview);
591
592 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
593 0, 2, &viewportOffsets[0]);
594
595 glDrawArrays(GL_TRIANGLES, 0, 3);
596 EXPECT_GL_NO_ERROR();
597
598 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
599 EXPECT_GL_NO_ERROR();
600 }
601}
602
Martin Radev7e69f762017-07-27 14:54:13 +0300603// The test verifies that glDraw*:
604// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
605// greater than 1 and there is an active transform feedback object.
606// 2) does not generate any error if the number of views in the draw framebuffer is 1.
607TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
608{
609 if (!requestMultiviewExtension())
610 {
611 return;
612 }
613
614 const GLint viewportOffsets[4] = {0, 0, 2, 0};
615
616 const std::string &vsSource =
617 "#version 300 es\n"
618 "void main()\n"
619 "{}\n";
620 const std::string &fsSource =
621 "#version 300 es\n"
622 "precision mediump float;\n"
623 "void main()\n"
624 "{}\n";
625 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
626 glUseProgram(program);
627
628 GLBuffer tbo;
629 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
630 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4u, nullptr, GL_STATIC_DRAW);
631
632 GLTransformFeedback transformFeedback;
633 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
634 glBeginTransformFeedback(GL_TRIANGLES);
635 ASSERT_GL_NO_ERROR();
636
637 // Check that drawArrays generates an error when there is an active transform feedback object
638 // and the number of views in the draw framebuffer is greater than 1.
639 {
640 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
641 0, 2, &viewportOffsets[0]);
642 glDrawArrays(GL_TRIANGLES, 0, 3);
643 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
644 }
645
646 // Check that drawArrays does not generate an error when the number of views in the draw
647 // framebuffer is 1.
648 {
649 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
650 0, 1, &viewportOffsets[0]);
651 glDrawArrays(GL_TRIANGLES, 0, 3);
652 EXPECT_GL_NO_ERROR();
653 }
654
655 glEndTransformFeedback();
656}
657
Martin Radevffe754b2017-07-31 10:38:07 +0300658// The test verifies that glDraw*:
659// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
660// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
661// 2) does not generate any error if the number of views in the draw framebuffer is 1.
662TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
663{
664 if (!requestMultiviewExtension())
665 {
666 return;
667 }
668
669 if (!extensionEnabled("GL_EXT_disjoint_timer_query"))
670 {
671 std::cout << "Test skipped because GL_EXT_disjoint_timer_query is not available."
672 << std::endl;
673 return;
674 }
675
676 const GLint viewportOffsets[4] = {0, 0, 2, 0};
677 const std::string &vsSource =
678 "#version 300 es\n"
679 "void main()\n"
680 "{}\n";
681 const std::string &fsSource =
682 "#version 300 es\n"
683 "precision mediump float;\n"
684 "void main()\n"
685 "{}\n";
686 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
687 glUseProgram(program);
688
689 GLuint query = 0u;
690 glGenQueriesEXT(1, &query);
691 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
692
693 // Check first case.
694 {
695 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
696 0, 2, &viewportOffsets[0]);
697 glDrawArrays(GL_TRIANGLES, 0, 3);
698 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
699 }
700
701 // Check second case.
702 {
703 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
704 0, 1, &viewportOffsets[0]);
705 glDrawArrays(GL_TRIANGLES, 0, 3);
706 EXPECT_GL_NO_ERROR();
707 }
708
709 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
710 glDeleteQueries(1, &query);
711}
712
Martin Radev8f276e22017-05-30 12:05:52 +0300713// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300714TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300715{
716 if (!requestMultiviewExtension())
717 {
718 return;
719 }
720 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
721 ASSERT_GL_NO_ERROR();
722
723 checkOutput();
724}
725
726// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300727TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300728{
729 if (!requestMultiviewExtension())
730 {
731 return;
732 }
733 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
734 ASSERT_GL_NO_ERROR();
735
736 checkOutput();
737}
738
739// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300740TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300741{
742 if (!requestMultiviewExtension())
743 {
744 return;
745 }
746 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
747 ASSERT_GL_NO_ERROR();
748
749 checkOutput();
750}
751
752// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300753TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300754{
755 if (!requestMultiviewExtension())
756 {
757 return;
758 }
759
760 const std::string vsSource =
761 "#version 300 es\n"
762 "#extension GL_OVR_multiview2 : require\n"
763 "layout(num_views = 4) in;\n"
764 "in vec4 vPosition;\n"
765 "void main()\n"
766 "{\n"
767 " if (gl_ViewID_OVR == 0u) {\n"
768 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
769 " } else if (gl_ViewID_OVR == 1u) {\n"
770 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
771 " } else if (gl_ViewID_OVR == 2u) {\n"
772 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
773 " } else {\n"
774 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
775 " }"
776 " gl_Position.yzw = vPosition.yzw;\n"
777 "}\n";
778
779 const std::string fsSource =
780 "#version 300 es\n"
781 "#extension GL_OVR_multiview2 : require\n"
782 "precision mediump float;\n"
783 "out vec4 col;\n"
784 "void main()\n"
785 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300786 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300787 "}\n";
788
Martin Radev3c25ad02017-08-22 17:36:53 +0300789 createFBO(4, 1, 4);
Martin Radev8f276e22017-05-30 12:05:52 +0300790 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
791 glUseProgram(program);
792
793 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
794 ASSERT_GL_NO_ERROR();
795
796 for (int i = 0; i < 4; ++i)
797 {
798 for (int j = 0; j < 4; ++j)
799 {
Martin Radev8f276e22017-05-30 12:05:52 +0300800 if (i == j)
801 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300802 EXPECT_EQ(GLColor::red, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300803 }
804 else
805 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300806 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300807 }
808 }
809 }
810 EXPECT_GL_NO_ERROR();
811}
812
813// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300814TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +0300815{
816 if (!requestMultiviewExtension())
817 {
818 return;
819 }
820
821 const std::string vsSource =
822 "#version 300 es\n"
823 "#extension GL_OVR_multiview : require\n"
824 "layout(num_views = 2) in;\n"
825 "in vec4 vPosition;\n"
826 "void main()\n"
827 "{\n"
828 " vec4 p = vPosition;\n"
829 " if (gl_InstanceID == 1){\n"
830 " p.y = .5*p.y + .5;\n"
831 " } else {\n"
832 " p.y = p.y*.5;\n"
833 " }\n"
834 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x*0.5 + 0.5 : p.x*0.5);\n"
835 " gl_Position.yzw = p.yzw;\n"
836 "}\n";
837
838 const std::string fsSource =
839 "#version 300 es\n"
840 "#extension GL_OVR_multiview : require\n"
841 "precision mediump float;\n"
842 "out vec4 col;\n"
843 "void main()\n"
844 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300845 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300846 "}\n";
847
Martin Radev3c25ad02017-08-22 17:36:53 +0300848 const int kViewWidth = 2;
849 const int kViewHeight = 2;
850 const int kNumViews = 2;
851 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev8f276e22017-05-30 12:05:52 +0300852 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
853 glUseProgram(program);
854
855 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 2);
856 ASSERT_GL_NO_ERROR();
857
Martin Radev3c25ad02017-08-22 17:36:53 +0300858 const GLubyte expectedRedChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
859 {{255, 0}, {255, 0}}};
860
861 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +0300862 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300863 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +0300864 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300865 for (int x = 0; x < 2; ++x)
866 {
867 EXPECT_EQ(GLColor(expectedRedChannel[view][y][x], 0, 0, 255),
868 GetViewColor(x, y, view));
869 }
Martin Radev8f276e22017-05-30 12:05:52 +0300870 }
871 }
872}
873
Martin Radev553590a2017-07-31 16:40:39 +0300874// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
875// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
876// offset of each quad are passed as separate attributes which are indexed based on the
877// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
878// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
879// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
880// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +0300881TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +0300882{
883 if (!requestMultiviewExtension())
884 {
885 return;
886 }
887
888 const std::string &vsSource =
889 "#version 300 es\n"
890 "#extension GL_OVR_multiview2 : require\n"
891 "layout(num_views = 2) in;\n"
892 "in vec3 vPosition;\n"
893 "in float offsetX;\n"
894 "in float offsetY;\n"
895 "void main()\n"
896 "{\n"
897 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +0300898 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300899 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
900 " gl_Position.yzw = p.yzw;\n"
901 "}\n";
902
903 const std::string &fsSource =
904 "#version 300 es\n"
905 "#extension GL_OVR_multiview2 : require\n"
906 "precision mediump float;\n"
907 "out vec4 col;\n"
908 "void main()\n"
909 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300910 " col = vec4(1,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300911 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +0300912
913 const int kViewWidth = 4;
914 const int kViewHeight = 4;
915 const int kNumViews = 2;
916 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev553590a2017-07-31 16:40:39 +0300917 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
918 glUseProgram(program);
919
920 GLBuffer xOffsetVBO;
921 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
922 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
923 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
924 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
925 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
926 glVertexAttribDivisor(xOffsetLoc, 3);
927 glEnableVertexAttribArray(xOffsetLoc);
928
929 GLBuffer yOffsetVBO;
930 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
931 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
932 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
933 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
934 glVertexAttribDivisor(yOffsetLoc, 1);
935 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
936 glEnableVertexAttribArray(yOffsetLoc);
937
938 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
939 ASSERT_GL_NO_ERROR();
940
Martin Radev3c25ad02017-08-22 17:36:53 +0300941 const GLubyte expectedRedChannel[kNumViews][kViewHeight][kViewWidth] = {
942 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
943 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
944 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +0300945 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300946 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +0300947 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300948 for (int col = 0; col < 4; ++col)
949 {
950 EXPECT_EQ(GLColor(expectedRedChannel[view][row][col], 0, 0, 255),
951 GetViewColor(col, row, view));
952 }
Martin Radev553590a2017-07-31 16:40:39 +0300953 }
954 }
955}
956
957// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
958// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +0300959TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +0300960{
961 if (!requestMultiviewExtension())
962 {
963 return;
964 }
965
Martin Radev3c25ad02017-08-22 17:36:53 +0300966 createFBO(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +0300967
968 // Create multiview program.
969 const std::string &vs =
970 "#version 300 es\n"
971 "#extension GL_OVR_multiview2 : require\n"
972 "layout(num_views = 2) in;\n"
973 "layout(location = 0) in vec2 vPosition;\n"
974 "layout(location = 1) in float offsetX;\n"
975 "void main()\n"
976 "{\n"
977 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
978 " p.x += offsetX;\n"
979 " gl_Position = p;\n"
980 "}\n";
981
982 const std::string &fs =
983 "#version 300 es\n"
984 "#extension GL_OVR_multiview2 : require\n"
985 "precision mediump float;\n"
986 "out vec4 col;\n"
987 "void main()\n"
988 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300989 " col = vec4(1,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300990 "}\n";
991
992 ANGLE_GL_PROGRAM(program, vs, fs);
993
994 const std::string &dummyVS =
995 "#version 300 es\n"
996 "layout(location = 0) in vec2 vPosition;\n"
997 "layout(location = 1) in float offsetX;\n"
998 "void main()\n"
999 "{\n"
1000 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1001 "}\n";
1002
1003 const std::string &dummyFS =
1004 "#version 300 es\n"
1005 "precision mediump float;\n"
1006 "out vec4 col;\n"
1007 "void main()\n"
1008 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001009 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001010 "}\n";
1011
1012 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
1013
1014 GLBuffer xOffsetVBO;
1015 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1016 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1017 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1018 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1019
1020 GLBuffer vertexVBO;
1021 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1022 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1023 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1024 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1025
1026 GLVertexArray vao[2];
1027 for (size_t i = 0u; i < 2u; ++i)
1028 {
1029 glBindVertexArray(vao[i]);
1030
1031 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1032 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1033 glEnableVertexAttribArray(0);
1034
1035 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1036 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1037 glEnableVertexAttribArray(1);
1038 }
1039 ASSERT_GL_NO_ERROR();
1040
1041 glViewport(0, 0, 1, 1);
1042 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001043 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001044 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001045
1046 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1047 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1048 // bits are cleared.
1049 glUseProgram(dummyProgram);
1050 glBindVertexArray(vao[0]);
1051 glVertexAttribDivisor(1, 0);
1052 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1053 glUseProgram(0);
1054 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1055 ASSERT_GL_NO_ERROR();
1056
1057 // Check that vertexAttribDivisor uses the number of views to update the divisor.
1058 glUseProgram(program);
1059 glVertexAttribDivisor(1, 1);
1060 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001061 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1062 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001063
1064 // Clear the buffers and propagate divisor to the driver.
1065 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1066 // dirty bits when useProgram is called.
1067 glUseProgram(dummyProgram);
1068 glVertexAttribDivisor(1, 1);
1069 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1070 glUseProgram(0);
1071 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1072 ASSERT_GL_NO_ERROR();
1073
1074 // Check that useProgram uses the number of views to update the divisor.
1075 glUseProgram(program);
1076 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001077 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1078 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001079
1080 // We go through similar steps as before.
1081 glUseProgram(dummyProgram);
1082 glVertexAttribDivisor(1, 1);
1083 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1084 glUseProgram(0);
1085 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1086 ASSERT_GL_NO_ERROR();
1087
1088 // Check that bindVertexArray uses the number of views to update the divisor.
1089 {
1090 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1091 // divisor for vao[1] only.
1092 glBindVertexArray(vao[1]);
1093 glUseProgram(program);
1094 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1095 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1096 glBindVertexArray(0);
1097 ASSERT_GL_NO_ERROR();
1098 }
1099 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1100 // adjusts the divisor.
1101 glBindVertexArray(vao[0]);
1102 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001103 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1104 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001105}
1106
Martin Radev0d671c92017-08-10 16:41:52 +03001107// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1108// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001109TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001110{
1111 if (!requestMultiviewExtension())
1112 {
1113 return;
1114 }
1115
1116 const std::string vsSource =
1117 "#version 300 es\n"
1118 "#extension GL_OVR_multiview : require\n"
1119 "layout(num_views = 2) in;\n"
1120 "in vec3 vPosition;\n"
1121 "void main()\n"
1122 "{\n"
1123 " gl_Position.x = 2.0;\n"
1124 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1125 "}\n";
1126
1127 const std::string fsSource =
1128 "#version 300 es\n"
1129 "#extension GL_OVR_multiview : require\n"
1130 "precision mediump float;\n"
1131 "out vec4 col;\n"
1132 "void main()\n"
1133 "{\n"
1134 " col = vec4(1,0,0,0);\n"
1135 "}\n";
1136 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1137 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001138 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001139
1140 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1141 ASSERT_GL_NO_ERROR();
1142 EXPECT_GL_FALSE(result);
1143}
1144
1145// Test that there are fragments passing the occlusion query if only view 0 can produce
1146// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001147TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001148{
1149 if (!requestMultiviewExtension())
1150 {
1151 return;
1152 }
1153
1154 const std::string vsSource =
1155 "#version 300 es\n"
1156 "#extension GL_OVR_multiview : require\n"
1157 "layout(num_views = 2) in;\n"
1158 "in vec3 vPosition;\n"
1159 "void main()\n"
1160 "{\n"
1161 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1162 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1163 "}\n";
1164
1165 const std::string fsSource =
1166 "#version 300 es\n"
1167 "#extension GL_OVR_multiview : require\n"
1168 "precision mediump float;\n"
1169 "out vec4 col;\n"
1170 "void main()\n"
1171 "{\n"
1172 " col = vec4(1,0,0,0);\n"
1173 "}\n";
1174 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1175 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001176 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001177
1178 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1179 ASSERT_GL_NO_ERROR();
1180 EXPECT_GL_TRUE(result);
1181}
1182
1183// Test that there are fragments passing the occlusion query if only view 1 can produce
1184// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001185TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001186{
1187 if (!requestMultiviewExtension())
1188 {
1189 return;
1190 }
1191
1192 const std::string vsSource =
1193 "#version 300 es\n"
1194 "#extension GL_OVR_multiview : require\n"
1195 "layout(num_views = 2) in;\n"
1196 "in vec3 vPosition;\n"
1197 "void main()\n"
1198 "{\n"
1199 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1200 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1201 "}\n";
1202
1203 const std::string fsSource =
1204 "#version 300 es\n"
1205 "#extension GL_OVR_multiview : require\n"
1206 "precision mediump float;\n"
1207 "out vec4 col;\n"
1208 "void main()\n"
1209 "{\n"
1210 " col = vec4(1,0,0,0);\n"
1211 "}\n";
1212 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1213 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001214 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001215
1216 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1217 ASSERT_GL_NO_ERROR();
1218 EXPECT_GL_TRUE(result);
1219}
1220
Martin Radev41ac68e2017-06-06 12:16:58 +03001221// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1222// compiles and links without an error.
1223TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1224{
1225 if (!requestMultiviewExtension())
1226 {
1227 return;
1228 }
1229
1230 const std::string vsSource =
1231 "#version 300 es\n"
1232 "#extension GL_OVR_multiview : require\n"
1233 "layout(num_views = 2) in;\n"
1234 "void main()\n"
1235 "{\n"
1236 "}\n";
1237
1238 const std::string fsSource =
1239 "#version 300 es\n"
1240 "#extension GL_OVR_multiview : require\n"
1241 "precision mediump float;\n"
1242 "void main()\n"
1243 "{\n"
1244 "}\n";
1245
1246 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1247 glUseProgram(program);
1248
1249 EXPECT_GL_NO_ERROR();
1250}
1251
1252// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1253// without an error.
1254TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1255{
1256 if (!requestMultiviewExtension())
1257 {
1258 return;
1259 }
1260
1261 const std::string vsSource =
1262 "#version 300 es\n"
1263 "#extension GL_OVR_multiview2 : require\n"
1264 "layout(num_views = 2) in;\n"
1265 "void main()\n"
1266 "{\n"
1267 " if (gl_ViewID_OVR == 0u) {\n"
1268 " gl_Position = vec4(1,0,0,1);\n"
1269 " } else {\n"
1270 " gl_Position = vec4(-1,0,0,1);\n"
1271 " }\n"
1272 "}\n";
1273
1274 const std::string fsSource =
1275 "#version 300 es\n"
1276 "#extension GL_OVR_multiview2 : require\n"
1277 "precision mediump float;\n"
1278 "void main()\n"
1279 "{\n"
1280 "}\n";
1281
1282 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1283 glUseProgram(program);
1284
1285 EXPECT_GL_NO_ERROR();
1286}
1287
1288// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1289// without an error.
1290TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1291{
1292 if (!requestMultiviewExtension())
1293 {
1294 return;
1295 }
1296
1297 const std::string vsSource =
1298 "#version 300 es\n"
1299 "#extension GL_OVR_multiview2 : require\n"
1300 "layout(num_views = 2) in;\n"
1301 "void main()\n"
1302 "{\n"
1303 "}\n";
1304
1305 const std::string fsSource =
1306 "#version 300 es\n"
1307 "#extension GL_OVR_multiview2 : require\n"
1308 "precision mediump float;\n"
1309 "out vec4 col;\n"
1310 "void main()\n"
1311 "{\n"
1312 " if (gl_ViewID_OVR == 0u) {\n"
1313 " col = vec4(1,0,0,1);\n"
1314 " } else {\n"
1315 " col = vec4(-1,0,0,1);\n"
1316 " }\n"
1317 "}\n";
1318
1319 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1320 glUseProgram(program);
1321
1322 EXPECT_GL_NO_ERROR();
1323}
1324
Martin Radev61bd9992017-08-11 13:10:55 +03001325// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001326TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001327{
1328 if (!requestMultiviewExtension())
1329 {
1330 return;
1331 }
1332
1333 const std::string vsSource =
1334 "#version 300 es\n"
1335 "#extension GL_OVR_multiview : require\n"
1336 "layout(num_views = 2) in;\n"
1337 "layout(location=0) in vec2 vPosition;\n"
1338 "void main()\n"
1339 "{\n"
1340 " gl_PointSize = 1.0;\n"
1341 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1342 "}\n";
1343
1344 const std::string fsSource =
1345 "#version 300 es\n"
1346 "#extension GL_OVR_multiview : require\n"
1347 "precision mediump float;\n"
1348 "out vec4 col;\n"
1349 "void main()\n"
1350 "{\n"
1351 " col = vec4(1,0,0,1);\n"
1352 "}\n";
1353 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1354 glUseProgram(program);
1355
Martin Radev3c25ad02017-08-22 17:36:53 +03001356 const int kViewWidth = 4;
1357 const int kViewHeight = 2;
1358 const int kNumViews = 2;
1359 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001360
1361 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1362 std::vector<Vector2> vertexDataInClipSpace =
1363 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1364 setupGeometry(vertexDataInClipSpace);
1365
1366 glDrawArrays(GL_POINTS, 0, 2);
1367
Martin Radev3c25ad02017-08-22 17:36:53 +03001368 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1369 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
1370 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001371}
1372
1373// The test checks that GL_LINES is correctly rendered.
1374// The behavior of this test is not guaranteed by the spec:
1375// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1376// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1377// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1378// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001379TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001380{
1381 if (!requestMultiviewExtension())
1382 {
1383 return;
1384 }
1385
1386 GLuint program = CreateSimplePassthroughProgram();
1387 ASSERT_NE(program, 0u);
1388 glUseProgram(program);
1389 ASSERT_GL_NO_ERROR();
1390
Martin Radev3c25ad02017-08-22 17:36:53 +03001391 const int kViewWidth = 4;
1392 const int kViewHeight = 2;
1393 const int kNumViews = 2;
1394 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001395
1396 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1397 std::vector<Vector2> vertexDataInClipSpace =
1398 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1399 setupGeometry(vertexDataInClipSpace);
1400
1401 glDrawArrays(GL_LINES, 0, 2);
1402
Martin Radev3c25ad02017-08-22 17:36:53 +03001403 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1404 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
1405 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001406
1407 glDeleteProgram(program);
1408}
1409
1410// The test checks that GL_LINE_STRIP is correctly rendered.
1411// The behavior of this test is not guaranteed by the spec:
1412// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1413// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1414// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1415// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001416TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001417{
1418 if (!requestMultiviewExtension())
1419 {
1420 return;
1421 }
1422
1423 GLuint program = CreateSimplePassthroughProgram();
1424 ASSERT_NE(program, 0u);
1425 glUseProgram(program);
1426 ASSERT_GL_NO_ERROR();
1427
Martin Radev3c25ad02017-08-22 17:36:53 +03001428 const int kViewWidth = 4;
1429 const int kViewHeight = 2;
1430 const int kNumViews = 2;
1431 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001432
1433 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1434 std::vector<Vector2> vertexDataInClipSpace =
1435 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1436 setupGeometry(vertexDataInClipSpace);
1437
1438 glDrawArrays(GL_LINE_STRIP, 0, 3);
1439
Martin Radev3c25ad02017-08-22 17:36:53 +03001440 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1441 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
1442 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001443
1444 glDeleteProgram(program);
1445}
1446
1447// The test checks that GL_LINE_LOOP is correctly rendered.
1448// The behavior of this test is not guaranteed by the spec:
1449// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1450// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1451// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1452// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001453TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001454{
1455 if (!requestMultiviewExtension())
1456 {
1457 return;
1458 }
1459
1460 GLuint program = CreateSimplePassthroughProgram();
1461 ASSERT_NE(program, 0u);
1462 glUseProgram(program);
1463 ASSERT_GL_NO_ERROR();
1464
Martin Radev3c25ad02017-08-22 17:36:53 +03001465 const int kViewWidth = 4;
1466 const int kViewHeight = 4;
1467 const int kNumViews = 2;
1468 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001469
1470 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1471 Vector2I(0, 3)};
1472 std::vector<Vector2> vertexDataInClipSpace =
1473 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1474 setupGeometry(vertexDataInClipSpace);
1475
1476 glDrawArrays(GL_LINE_LOOP, 0, 4);
1477
Martin Radev3c25ad02017-08-22 17:36:53 +03001478 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1479 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1480 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
1481 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001482
1483 glDeleteProgram(program);
1484}
1485
1486// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001487TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001488{
1489 if (!requestMultiviewExtension())
1490 {
1491 return;
1492 }
1493
1494 GLuint program = CreateSimplePassthroughProgram();
1495 ASSERT_NE(program, 0u);
1496 glUseProgram(program);
1497 ASSERT_GL_NO_ERROR();
1498
1499 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1500 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1501 setupGeometry(vertexDataInClipSpace);
1502
Martin Radev3c25ad02017-08-22 17:36:53 +03001503 const int kViewWidth = 2;
1504 const int kViewHeight = 2;
1505 const int kNumViews = 2;
1506 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001507
1508 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1509
Martin Radev3c25ad02017-08-22 17:36:53 +03001510 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {{{0, 0}, {0, 255}},
1511 {{0, 0}, {0, 255}}};
1512 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001513
1514 glDeleteProgram(program);
1515}
1516
1517// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001518TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001519{
1520 if (!requestMultiviewExtension())
1521 {
1522 return;
1523 }
1524
1525 GLuint program = CreateSimplePassthroughProgram();
1526 ASSERT_NE(program, 0u);
1527 glUseProgram(program);
1528 ASSERT_GL_NO_ERROR();
1529
1530 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1531 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1532 setupGeometry(vertexDataInClipSpace);
1533
Martin Radev3c25ad02017-08-22 17:36:53 +03001534 const int kViewWidth = 2;
1535 const int kViewHeight = 2;
1536 const int kNumViews = 2;
1537 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001538
1539 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1540
Martin Radev3c25ad02017-08-22 17:36:53 +03001541 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {{{0, 0}, {0, 255}},
1542 {{0, 0}, {0, 255}}};
1543 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001544
1545 glDeleteProgram(program);
1546}
1547
1548// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1549// bounds. The test does not rely on the actual line width being greater than 1.0.
Martin Radev3c25ad02017-08-22 17:36:53 +03001550TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
Martin Radev61bd9992017-08-11 13:10:55 +03001551{
1552 if (!requestMultiviewExtension())
1553 {
1554 return;
1555 }
1556
Martin Radev3c25ad02017-08-22 17:36:53 +03001557 createFBO(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +03001558
1559 GLint viewportOffsets[4] = {1, 0, 3, 0};
1560 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1561 mColorTexture, 0, 2, &viewportOffsets[0]);
1562 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
1563 mDepthTexture, 0, 2, &viewportOffsets[0]);
1564
1565 glViewport(0, 0, 1, 1);
1566 glScissor(0, 0, 1, 1);
1567 glEnable(GL_SCISSOR_TEST);
1568
1569 const std::string vsSource =
1570 "#version 300 es\n"
1571 "#extension GL_OVR_multiview2 : require\n"
1572 "layout(num_views = 2) in;\n"
1573 "layout(location=0) in vec2 vPosition;\n"
1574 "void main()\n"
1575 "{\n"
1576 " gl_PointSize = 10.0;\n"
1577 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1578 "}\n";
1579
1580 const std::string fsSource =
1581 "#version 300 es\n"
1582 "#extension GL_OVR_multiview2 : require\n"
1583 "precision mediump float;\n"
1584 "out vec4 col;\n"
1585 "void main()\n"
1586 "{\n"
1587 " if (gl_ViewID_OVR == 0u) {\n"
1588 " col = vec4(1,0,0,1);\n"
1589 " } else {\n"
1590 " col = vec4(0,1,0,1);\n"
1591 " }\n"
1592 "}\n";
1593 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1594 glUseProgram(program);
1595
1596 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1597 const std::vector<Vector2> &vertexDataInClipSpace =
1598 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001599
1600 GLBuffer vbo;
1601 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1602 glBufferData(GL_ARRAY_BUFFER, vertexDataInClipSpace.size() * sizeof(Vector2),
1603 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1604 glEnableVertexAttribArray(0);
1605 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
Martin Radev61bd9992017-08-11 13:10:55 +03001606
1607 // Test rendering points.
1608 {
1609 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1610 glDrawArrays(GL_POINTS, 0, 2);
1611 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1612 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1613 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1614 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1615 }
1616
1617 // Test rendering lines.
1618 {
1619 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1620 glLineWidth(10.f);
1621 glDrawArrays(GL_LINES, 0, 2);
1622 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1623 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1624 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1625 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1626 }
1627}
1628
Martin Radev0abb7a22017-08-28 15:34:45 +03001629// Verify that re-linking a program adjusts the attribute divisor.
1630// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1631// to each other. The quads' position and color depend on the corresponding attribute divisors.
1632TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1633{
1634 if (!requestMultiviewExtension())
1635 {
1636 return;
1637 }
1638
1639 const int kViewWidth = 4;
1640 const int kViewHeight = 1;
1641 const int kNumViews = 2;
1642
1643 const std::string &fsSource =
1644 "#version 300 es\n"
1645 "#extension GL_OVR_multiview2 : require\n"
1646 "precision mediump float;\n"
1647 "in vec4 oColor;\n"
1648 "out vec4 col;\n"
1649 "void main()\n"
1650 "{\n"
1651 " col = oColor;\n"
1652 "}\n";
1653
1654 auto generateVertexShaderSource = [](int numViews) -> std::string {
1655 std::string source =
1656 "#version 300 es\n"
1657 "#extension GL_OVR_multiview2 : require\n"
1658 "layout(num_views = " +
1659 ToString(numViews) +
1660 ") in;\n"
1661 "in vec3 vPosition;\n"
1662 "in float vOffsetX;\n"
1663 "in vec4 vColor;\n"
1664 "out vec4 oColor;\n"
1665 "void main()\n"
1666 "{\n"
1667 " vec4 p = vec4(vPosition, 1.);\n"
1668 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1669 " oColor = vColor;\n"
1670 " gl_Position = p;\n"
1671 "}\n";
1672 return source;
1673 };
1674
1675 std::string vsSource = generateVertexShaderSource(kNumViews);
1676 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1677 glUseProgram(program);
1678
1679 GLint positionLoc;
1680 GLBuffer xOffsetVBO;
1681 GLint xOffsetLoc;
1682 GLBuffer colorVBO;
1683 GLint colorLoc;
1684
1685 {
1686 // Initialize buffers and setup attributes.
1687 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1688 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1689 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1690 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1691 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1692 glVertexAttribDivisor(xOffsetLoc, 1);
1693 glEnableVertexAttribArray(xOffsetLoc);
1694
1695 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1696 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1697 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1698 colorLoc = glGetAttribLocation(program, "vColor");
1699 glVertexAttribDivisor(colorLoc, 2);
1700 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1701 glEnableVertexAttribArray(colorLoc);
1702
1703 positionLoc = glGetAttribLocation(program, "vPosition");
1704 }
1705
1706 {
1707 createFBO(kViewWidth, kViewHeight, kNumViews);
1708
1709 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
1710 ASSERT_GL_NO_ERROR();
1711
1712 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1713 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1714 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1715 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1716 }
1717
1718 {
1719 const int kNewNumViews = 3;
1720 vsSource = generateVertexShaderSource(kNewNumViews);
1721 createFBO(kViewWidth, kViewHeight, kNewNumViews);
1722
1723 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
1724 ASSERT_NE(0u, vs);
1725 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
1726 ASSERT_NE(0u, fs);
1727
1728 GLint numAttachedShaders = 0;
1729 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1730
1731 GLuint attachedShaders[2] = {0u};
1732 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1733 for (int i = 0; i < 2; ++i)
1734 {
1735 glDetachShader(program, attachedShaders[i]);
1736 }
1737
1738 glAttachShader(program, vs);
1739 glDeleteShader(vs);
1740
1741 glAttachShader(program, fs);
1742 glDeleteShader(fs);
1743
1744 glBindAttribLocation(program, positionLoc, "vPosition");
1745 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1746 glBindAttribLocation(program, colorLoc, "vColor");
1747
1748 glLinkProgram(program);
1749
1750 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
1751 ASSERT_GL_NO_ERROR();
1752
1753 for (int i = 0; i < kNewNumViews; ++i)
1754 {
1755 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1756 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1757 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1758 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1759 }
1760 }
1761}
1762
Martin Radev3c25ad02017-08-22 17:36:53 +03001763MultiviewTestParams SideBySideOpenGL()
1764{
1765 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, egl_platform::OPENGL());
1766}
1767
1768MultiviewTestParams LayeredOpenGL()
1769{
1770 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, egl_platform::OPENGL());
1771}
1772
1773MultiviewTestParams SideBySideD3D11()
1774{
1775 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, egl_platform::D3D11());
1776}
1777
Martin Radev8f276e22017-05-30 12:05:52 +03001778ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest, ES31_OPENGL());
Martin Radev3c25ad02017-08-22 17:36:53 +03001779ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest, SideBySideOpenGL(), LayeredOpenGL());
1780ANGLE_INSTANTIATE_TEST(MultiviewRenderTest, SideBySideOpenGL(), LayeredOpenGL());
1781ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest, SideBySideOpenGL(), LayeredOpenGL());
1782ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest, SideBySideOpenGL(), SideBySideD3D11());
1783ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest, SideBySideOpenGL(), LayeredOpenGL());
Martin Radev0d671c92017-08-10 16:41:52 +03001784ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest, ES3_OPENGL());