blob: 164fa04f070142c08aa14470378280245ae65252 [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{
Martin Radevced5c862017-08-17 16:05:29 +030017GLuint CreateSimplePassthroughProgram(int numViews)
Martin Radev61bd9992017-08-11 13:10:55 +030018{
19 const std::string vsSource =
20 "#version 300 es\n"
21 "#extension GL_OVR_multiview : require\n"
Martin Radevced5c862017-08-17 16:05:29 +030022 "layout(num_views = " +
23 ToString(numViews) +
24 ") in;\n"
Martin Radev61bd9992017-08-11 13:10:55 +030025 "layout(location=0) in vec2 vPosition;\n"
26 "void main()\n"
27 "{\n"
Martin Radevced5c862017-08-17 16:05:29 +030028 " gl_PointSize = 1.;\n"
Martin Radev61bd9992017-08-11 13:10:55 +030029 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
30 "}\n";
31
32 const std::string fsSource =
33 "#version 300 es\n"
34 "#extension GL_OVR_multiview : require\n"
35 "precision mediump float;\n"
36 "out vec4 col;\n"
37 "void main()\n"
38 "{\n"
39 " col = vec4(1,0,0,1);\n"
40 "}\n";
41 return CompileProgram(vsSource, fsSource);
42}
43
44std::vector<Vector2> ConvertPixelCoordinatesToClipSpace(const std::vector<Vector2I> &pixels,
45 int width,
46 int height)
47{
48 std::vector<Vector2> result(pixels.size());
49 for (size_t i = 0; i < pixels.size(); ++i)
50 {
51 const auto &pixel = pixels[i];
52 float pixelCenterRelativeX = (static_cast<float>(pixel.x()) + .5f) / width;
53 float pixelCenterRelativeY = (static_cast<float>(pixel.y()) + .5f) / height;
54 float xInClipSpace = 2.f * pixelCenterRelativeX - 1.f;
55 float yInClipSpace = 2.f * pixelCenterRelativeY - 1.f;
56 result[i] = Vector2(xInClipSpace, yInClipSpace);
57 }
58 return result;
59}
60} // namespace
61
Martin Radev3c25ad02017-08-22 17:36:53 +030062struct MultiviewTestParams final : public PlatformParameters
63{
64 MultiviewTestParams(GLenum multiviewLayout, const EGLPlatformParameters &eglPlatformParameters)
65 : PlatformParameters(3, 0, eglPlatformParameters), mMultiviewLayout(multiviewLayout)
66 {
67 ASSERT(multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE ||
68 multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
69 }
70 GLenum mMultiviewLayout;
71};
72
73std::ostream &operator<<(std::ostream &os, const MultiviewTestParams &params)
74{
75 const PlatformParameters &base = static_cast<const PlatformParameters &>(params);
76 os << base;
77 switch (params.mMultiviewLayout)
78 {
79 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
80 os << "_layered";
81 break;
82 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
83 os << "_side_by_side";
84 break;
85 default:
86 UNREACHABLE();
87 }
88 return os;
89}
90
91class MultiviewDrawTest : public ANGLETestBase
Martin Radev14a26ae2017-07-24 15:56:29 +030092{
93 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +030094 MultiviewDrawTest(const PlatformParameters &params) : ANGLETestBase(params)
Martin Radev14a26ae2017-07-24 15:56:29 +030095 {
96 setWindowWidth(128);
97 setWindowHeight(128);
98 setWebGLCompatibilityEnabled(true);
99 }
Martin Radev7cf61662017-07-26 17:10:53 +0300100 virtual ~MultiviewDrawTest() {}
Martin Radev14a26ae2017-07-24 15:56:29 +0300101
Martin Radev3c25ad02017-08-22 17:36:53 +0300102 void DrawTestSetUp()
Martin Radev14a26ae2017-07-24 15:56:29 +0300103 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300104 ANGLETestBase::ANGLETestSetUp();
Martin Radev14a26ae2017-07-24 15:56:29 +0300105
106 glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
107 eglGetProcAddress("glRequestExtensionANGLE"));
108 }
109
110 // Requests the ANGLE_multiview extension and returns true if the operation succeeds.
111 bool requestMultiviewExtension()
112 {
113 if (extensionRequestable("GL_ANGLE_multiview"))
114 {
115 glRequestExtensionANGLE("GL_ANGLE_multiview");
116 }
117
118 if (!extensionEnabled("GL_ANGLE_multiview"))
119 {
120 std::cout << "Test skipped due to missing GL_ANGLE_multiview." << std::endl;
121 return false;
122 }
123 return true;
124 }
125
126 PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
127};
128
Martin Radev3c25ad02017-08-22 17:36:53 +0300129class MultiviewDrawValidationTest : public MultiviewDrawTest,
130 public ::testing::TestWithParam<PlatformParameters>
Martin Radev7cf61662017-07-26 17:10:53 +0300131{
132 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300133 MultiviewDrawValidationTest() : MultiviewDrawTest(GetParam()) {}
Martin Radev7cf61662017-07-26 17:10:53 +0300134
135 void SetUp() override
136 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300137 MultiviewDrawTest::DrawTestSetUp();
Martin Radev7cf61662017-07-26 17:10:53 +0300138
139 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
140
141 glBindTexture(GL_TEXTURE_2D, mTex2d);
142 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
143
144 glBindVertexArray(mVao);
145
146 const float kVertexData[3] = {0.0f};
147 glBindBuffer(GL_ARRAY_BUFFER, mVbo);
148 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
149
150 const unsigned int kIndices[3] = {0u, 1u, 2u};
151 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo);
152 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
153 GL_STATIC_DRAW);
154 ASSERT_GL_NO_ERROR();
155 }
156
157 GLTexture mTex2d;
158 GLVertexArray mVao;
159 GLBuffer mVbo;
160 GLBuffer mIbo;
161 GLFramebuffer mFramebuffer;
162};
163
Martin Radev3c25ad02017-08-22 17:36:53 +0300164class MultiviewRenderTestBase : public MultiviewDrawTest
Martin Radev8f276e22017-05-30 12:05:52 +0300165{
166 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300167 MultiviewRenderTestBase(const PlatformParameters &params, GLenum multiviewLayout)
168 : MultiviewDrawTest(params),
169 mMultiviewLayout(multiviewLayout),
170 mViewWidth(0),
171 mViewHeight(0),
172 mNumViews(0)
Martin Radev8f276e22017-05-30 12:05:52 +0300173 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300174 }
175 void RenderTestSetUp() { MultiviewDrawTest::DrawTestSetUp(); }
176 void createFBO(int viewWidth, int height, int numViews)
177 {
178 mViewWidth = viewWidth;
179 mViewHeight = height;
180 mNumViews = numViews;
Martin Radev8f276e22017-05-30 12:05:52 +0300181
Martin Radev0abb7a22017-08-28 15:34:45 +0300182 mColorTexture.reset();
183 mDepthTexture.reset();
184 mDrawFramebuffer.reset();
185 mReadFramebuffer.clear();
186
Martin Radev8f276e22017-05-30 12:05:52 +0300187 // Create color and depth textures.
Martin Radev3c25ad02017-08-22 17:36:53 +0300188 switch (mMultiviewLayout)
Martin Radev8f276e22017-05-30 12:05:52 +0300189 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300190 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
191 {
192 int textureWidth = viewWidth * numViews;
193 glBindTexture(GL_TEXTURE_2D, mColorTexture);
194 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, height, 0, GL_RGBA,
195 GL_UNSIGNED_BYTE, NULL);
196 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
197 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
198
199 glBindTexture(GL_TEXTURE_2D, mDepthTexture);
200 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, textureWidth, height, 0,
201 GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
202 glBindTexture(GL_TEXTURE_2D, 0);
203 break;
204 }
205 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
206 glBindTexture(GL_TEXTURE_2D_ARRAY, mColorTexture);
207 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, viewWidth, height, numViews, 0,
208 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
209 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
210 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
211
212 glBindTexture(GL_TEXTURE_2D_ARRAY, mDepthTexture);
213 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, viewWidth, height,
214 numViews, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
215 glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
216 break;
217 default:
218 UNREACHABLE();
Martin Radev8f276e22017-05-30 12:05:52 +0300219 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300220 ASSERT_GL_NO_ERROR();
221
222 // Create draw framebuffer to be used for multiview rendering.
223 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
224 switch (mMultiviewLayout)
225 {
226 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
227 {
228 std::vector<GLint> viewportOffsets(numViews * 2);
229 for (int i = 0u; i < numViews; ++i)
230 {
231 viewportOffsets[i * 2] = i * viewWidth;
232 viewportOffsets[i * 2 + 1] = 0;
233 }
234 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER,
235 GL_COLOR_ATTACHMENT0, mColorTexture, 0,
236 numViews, &viewportOffsets[0]);
237 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER,
238 GL_DEPTH_ATTACHMENT, mDepthTexture, 0,
239 numViews, &viewportOffsets[0]);
240 break;
241 }
242 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
243 glFramebufferTextureMultiviewLayeredANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
244 mColorTexture, 0, 0, numViews);
245 glFramebufferTextureMultiviewLayeredANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
246 mDepthTexture, 0, 0, numViews);
247 break;
248 default:
249 UNREACHABLE();
250 }
Martin Radev8f276e22017-05-30 12:05:52 +0300251
252 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
253 glDrawBuffers(1, DrawBuffers);
254 ASSERT_GL_NO_ERROR();
255 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
256
257 // Create read framebuffer to be used to retrieve the pixel information for testing
258 // purposes.
Martin Radev3c25ad02017-08-22 17:36:53 +0300259 switch (mMultiviewLayout)
260 {
261 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
262 mReadFramebuffer.resize(1);
263 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
264 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
265 mColorTexture, 0);
266 break;
267 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
268 mReadFramebuffer.resize(numViews);
269 for (int i = 0; i < numViews; ++i)
270 {
271 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
272 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
273 mColorTexture, 0, i);
274 }
275 break;
276 default:
277 UNREACHABLE();
278 }
Martin Radev8f276e22017-05-30 12:05:52 +0300279 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
280
281 // Clear the buffers.
Martin Radev3c25ad02017-08-22 17:36:53 +0300282 glViewport(0, 0, viewWidth, height);
283 if (mMultiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
284 {
285 // Enable the scissor test only for side-by-side framebuffers.
286 glEnable(GL_SCISSOR_TEST);
287 glScissor(0, 0, viewWidth, height);
288 }
Martin Radev61bd9992017-08-11 13:10:55 +0300289 glClearColor(0, 0, 0, 1);
Martin Radev8f276e22017-05-30 12:05:52 +0300290 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev3c25ad02017-08-22 17:36:53 +0300291 }
Martin Radev8f276e22017-05-30 12:05:52 +0300292
Martin Radev3c25ad02017-08-22 17:36:53 +0300293 GLColor GetViewColor(int x, int y, int view)
294 {
295 switch (mMultiviewLayout)
296 {
297 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
298 return ReadColor(view * mViewWidth + x, y);
299 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
300 ASSERT(static_cast<size_t>(view) < mReadFramebuffer.size());
301 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
302 return ReadColor(x, y);
303 default:
304 UNREACHABLE();
305 }
306 return GLColor(0, 0, 0, 0);
Martin Radev8f276e22017-05-30 12:05:52 +0300307 }
308
309 GLTexture mColorTexture;
310 GLTexture mDepthTexture;
311 GLFramebuffer mDrawFramebuffer;
Martin Radev3c25ad02017-08-22 17:36:53 +0300312 std::vector<GLFramebuffer> mReadFramebuffer;
313 GLenum mMultiviewLayout;
314 int mViewWidth;
315 int mViewHeight;
316 int mNumViews;
Martin Radev8f276e22017-05-30 12:05:52 +0300317};
318
Martin Radev3c25ad02017-08-22 17:36:53 +0300319class MultiviewRenderTest : public MultiviewRenderTestBase,
320 public ::testing::TestWithParam<MultiviewTestParams>
Martin Radev8f276e22017-05-30 12:05:52 +0300321{
322 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300323 MultiviewRenderTest() : MultiviewRenderTestBase(GetParam(), GetParam().mMultiviewLayout) {}
324 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
325};
326
327class MultiviewRenderDualViewTest : public MultiviewRenderTest
328{
329 protected:
330 MultiviewRenderDualViewTest() : mProgram(0u) {}
331 ~MultiviewRenderDualViewTest()
Martin Radev8f276e22017-05-30 12:05:52 +0300332 {
333 if (mProgram != 0u)
334 {
335 glDeleteProgram(mProgram);
336 }
337 }
338
339 void SetUp() override
340 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300341 MultiviewRenderTest::SetUp();
Martin Radev8f276e22017-05-30 12:05:52 +0300342
343 if (!requestMultiviewExtension())
344 {
345 return;
346 }
347
348 const std::string vsSource =
349 "#version 300 es\n"
350 "#extension GL_OVR_multiview : require\n"
351 "layout(num_views = 2) in;\n"
352 "in vec4 vPosition;\n"
353 "void main()\n"
354 "{\n"
355 " gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x*0.5 + 0.5 : vPosition.x*0.5);\n"
356 " gl_Position.yzw = vPosition.yzw;\n"
357 "}\n";
358
359 const std::string fsSource =
360 "#version 300 es\n"
361 "#extension GL_OVR_multiview : require\n"
362 "precision mediump float;\n"
363 "out vec4 col;\n"
364 "void main()\n"
365 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300366 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300367 "}\n";
368
Martin Radev3c25ad02017-08-22 17:36:53 +0300369 createFBO(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +0300370 mProgram = CompileProgram(vsSource, fsSource);
371 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300372 glUseProgram(mProgram);
373 ASSERT_GL_NO_ERROR();
374 }
375
376 void checkOutput()
377 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300378 EXPECT_EQ(GLColor::black, GetViewColor(0, 0, 0));
379 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
380 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
381 EXPECT_EQ(GLColor::black, GetViewColor(1, 0, 1));
Martin Radev8f276e22017-05-30 12:05:52 +0300382 }
383
384 GLuint mProgram;
385};
386
Martin Radev3c25ad02017-08-22 17:36:53 +0300387class MultiviewOcclusionQueryTest : public MultiviewRenderTest
Martin Radev0d671c92017-08-10 16:41:52 +0300388{
389 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300390 MultiviewOcclusionQueryTest() {}
Martin Radev0d671c92017-08-10 16:41:52 +0300391
392 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
393 {
394 GLuint query;
395 glGenQueries(1, &query);
396 glBeginQuery(GL_ANY_SAMPLES_PASSED, query);
397 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
398 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
399
400 GLuint result = GL_TRUE;
401 glGetQueryObjectuiv(query, GL_QUERY_RESULT, &result);
402 return result;
403 }
404};
405
Martin Radev3c25ad02017-08-22 17:36:53 +0300406class MultiviewProgramGenerationTest : public MultiviewRenderTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300407{
408 protected:
409 MultiviewProgramGenerationTest() {}
410};
411
Martin Radev3c25ad02017-08-22 17:36:53 +0300412class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300413{
414 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300415 MultiviewRenderPrimitiveTest() {}
Martin Radev61bd9992017-08-11 13:10:55 +0300416
417 void setupGeometry(const std::vector<Vector2> &vertexData)
418 {
Martin Radev61bd9992017-08-11 13:10:55 +0300419 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
420 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
421 GL_STATIC_DRAW);
422 glEnableVertexAttribArray(0);
423 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
424 }
425
Martin Radev3c25ad02017-08-22 17:36:53 +0300426 void checkRedChannel(const GLubyte expectedRedChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300427 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300428 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300429 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300430 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300431 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300432 for (int h = 0; h < mViewHeight; ++h)
433 {
434 size_t flatIndex =
435 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
436 EXPECT_EQ(GLColor(expectedRedChannelData[flatIndex], 0, 0, 255),
437 GetViewColor(w, h, view));
438 }
Martin Radev61bd9992017-08-11 13:10:55 +0300439 }
440 }
441 }
Martin Radev61bd9992017-08-11 13:10:55 +0300442 GLBuffer mVBO;
443};
444
Martin Radev3c25ad02017-08-22 17:36:53 +0300445class MultiviewSideBySideRenderTest : public MultiviewRenderTestBase,
446 public ::testing::TestWithParam<PlatformParameters>
447{
448 protected:
449 MultiviewSideBySideRenderTest()
450 : MultiviewRenderTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
451 {
452 }
453 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
454};
455
Martin Radev14a26ae2017-07-24 15:56:29 +0300456// The test verifies that glDraw*Indirect:
457// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
458// than 1.
459// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +0300460TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300461{
462 if (!requestMultiviewExtension())
463 {
464 return;
465 }
466
Martin Radev14a26ae2017-07-24 15:56:29 +0300467 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +0300468
469 const std::string fsSource =
470 "#version 300 es\n"
471 "#extension GL_OVR_multiview : require\n"
472 "precision mediump float;\n"
473 "void main()\n"
474 "{}\n";
475
Martin Radev14a26ae2017-07-24 15:56:29 +0300476 GLBuffer commandBuffer;
477 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
478 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
479 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
480 ASSERT_GL_NO_ERROR();
481
Martin Radev14a26ae2017-07-24 15:56:29 +0300482 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
483 {
484 const std::string &vsSource =
485 "#version 300 es\n"
486 "#extension GL_OVR_multiview : require\n"
487 "layout(num_views = 2) in;\n"
488 "void main()\n"
489 "{}\n";
490 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
491 glUseProgram(program);
492
Martin Radev7cf61662017-07-26 17:10:53 +0300493 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
494 0, 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300495
496 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
497 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
498
499 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
500 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
501 }
502
503 // Check that no errors are generated if the number of views is 1.
504 {
505 const std::string &vsSource =
506 "#version 300 es\n"
507 "#extension GL_OVR_multiview : require\n"
508 "layout(num_views = 1) in;\n"
509 "void main()\n"
510 "{}\n";
511 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
512 glUseProgram(program);
513
Martin Radev7cf61662017-07-26 17:10:53 +0300514 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
515 0, 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300516
517 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
518 EXPECT_GL_NO_ERROR();
519
520 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
521 EXPECT_GL_NO_ERROR();
522 }
523}
524
Martin Radev7cf61662017-07-26 17:10:53 +0300525// The test verifies that glDraw*:
526// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
527// program differs.
528// 2) does not generate any error if the number of views is the same.
529// 3) does not generate any error if the program does not use the multiview extension.
530TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
531{
532 if (!requestMultiviewExtension())
533 {
534 return;
535 }
536
537 const GLint viewportOffsets[4] = {0, 0, 2, 0};
538
539 const std::string &vsSource =
540 "#version 300 es\n"
541 "#extension GL_OVR_multiview : require\n"
542 "layout(num_views = 2) in;\n"
543 "void main()\n"
544 "{}\n";
545 const std::string &fsSource =
546 "#version 300 es\n"
547 "#extension GL_OVR_multiview : require\n"
548 "precision mediump float;\n"
549 "void main()\n"
550 "{}\n";
551 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
552 glUseProgram(program);
553
554 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
555 // number of views.
556 {
557 // The framebuffer has only 1 view.
558 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
559 0, 1, &viewportOffsets[0]);
560
561 glDrawArrays(GL_TRIANGLES, 0, 3);
562 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
563
564 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
565 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
566 }
567
568 // Check that no errors are generated if the number of views in both program and draw
569 // framebuffer matches.
570 {
571 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
572 0, 2, &viewportOffsets[0]);
573
574 glDrawArrays(GL_TRIANGLES, 0, 3);
575 EXPECT_GL_NO_ERROR();
576
577 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
578 EXPECT_GL_NO_ERROR();
579 }
580
581 // Check that no errors are generated if the program does not use the multiview extension.
582 {
583 const std::string &vsSourceNoMultiview =
584 "#version 300 es\n"
585 "void main()\n"
586 "{}\n";
587 const std::string &fsSourceNoMultiview =
588 "#version 300 es\n"
589 "precision mediump float;\n"
590 "void main()\n"
591 "{}\n";
592 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
593 glUseProgram(programNoMultiview);
594
595 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
596 0, 2, &viewportOffsets[0]);
597
598 glDrawArrays(GL_TRIANGLES, 0, 3);
599 EXPECT_GL_NO_ERROR();
600
601 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
602 EXPECT_GL_NO_ERROR();
603 }
604}
605
Martin Radev7e69f762017-07-27 14:54:13 +0300606// The test verifies that glDraw*:
607// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
608// greater than 1 and there is an active transform feedback object.
609// 2) does not generate any error if the number of views in the draw framebuffer is 1.
610TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
611{
612 if (!requestMultiviewExtension())
613 {
614 return;
615 }
616
617 const GLint viewportOffsets[4] = {0, 0, 2, 0};
618
619 const std::string &vsSource =
620 "#version 300 es\n"
621 "void main()\n"
622 "{}\n";
623 const std::string &fsSource =
624 "#version 300 es\n"
625 "precision mediump float;\n"
626 "void main()\n"
627 "{}\n";
628 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
629 glUseProgram(program);
630
631 GLBuffer tbo;
632 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
633 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4u, nullptr, GL_STATIC_DRAW);
634
635 GLTransformFeedback transformFeedback;
636 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
637 glBeginTransformFeedback(GL_TRIANGLES);
638 ASSERT_GL_NO_ERROR();
639
640 // Check that drawArrays generates an error when there is an active transform feedback object
641 // and the number of views in the draw framebuffer is greater than 1.
642 {
643 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
644 0, 2, &viewportOffsets[0]);
645 glDrawArrays(GL_TRIANGLES, 0, 3);
646 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
647 }
648
649 // Check that drawArrays does not generate an error when the number of views in the draw
650 // framebuffer is 1.
651 {
652 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
653 0, 1, &viewportOffsets[0]);
654 glDrawArrays(GL_TRIANGLES, 0, 3);
655 EXPECT_GL_NO_ERROR();
656 }
657
658 glEndTransformFeedback();
659}
660
Martin Radevffe754b2017-07-31 10:38:07 +0300661// The test verifies that glDraw*:
662// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
663// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
664// 2) does not generate any error if the number of views in the draw framebuffer is 1.
665TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
666{
667 if (!requestMultiviewExtension())
668 {
669 return;
670 }
671
672 if (!extensionEnabled("GL_EXT_disjoint_timer_query"))
673 {
674 std::cout << "Test skipped because GL_EXT_disjoint_timer_query is not available."
675 << std::endl;
676 return;
677 }
678
679 const GLint viewportOffsets[4] = {0, 0, 2, 0};
680 const std::string &vsSource =
681 "#version 300 es\n"
682 "void main()\n"
683 "{}\n";
684 const std::string &fsSource =
685 "#version 300 es\n"
686 "precision mediump float;\n"
687 "void main()\n"
688 "{}\n";
689 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
690 glUseProgram(program);
691
692 GLuint query = 0u;
693 glGenQueriesEXT(1, &query);
694 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
695
696 // Check first case.
697 {
698 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
699 0, 2, &viewportOffsets[0]);
700 glDrawArrays(GL_TRIANGLES, 0, 3);
701 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
702 }
703
704 // Check second case.
705 {
706 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
707 0, 1, &viewportOffsets[0]);
708 glDrawArrays(GL_TRIANGLES, 0, 3);
709 EXPECT_GL_NO_ERROR();
710 }
711
712 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
713 glDeleteQueries(1, &query);
714}
715
Martin Radev8f276e22017-05-30 12:05:52 +0300716// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300717TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300718{
719 if (!requestMultiviewExtension())
720 {
721 return;
722 }
723 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
724 ASSERT_GL_NO_ERROR();
725
726 checkOutput();
727}
728
729// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300730TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300731{
732 if (!requestMultiviewExtension())
733 {
734 return;
735 }
736 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
737 ASSERT_GL_NO_ERROR();
738
739 checkOutput();
740}
741
742// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300743TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300744{
745 if (!requestMultiviewExtension())
746 {
747 return;
748 }
749 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
750 ASSERT_GL_NO_ERROR();
751
752 checkOutput();
753}
754
755// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300756TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300757{
758 if (!requestMultiviewExtension())
759 {
760 return;
761 }
762
763 const std::string vsSource =
764 "#version 300 es\n"
765 "#extension GL_OVR_multiview2 : require\n"
766 "layout(num_views = 4) in;\n"
767 "in vec4 vPosition;\n"
768 "void main()\n"
769 "{\n"
770 " if (gl_ViewID_OVR == 0u) {\n"
771 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
772 " } else if (gl_ViewID_OVR == 1u) {\n"
773 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
774 " } else if (gl_ViewID_OVR == 2u) {\n"
775 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
776 " } else {\n"
777 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
778 " }"
779 " gl_Position.yzw = vPosition.yzw;\n"
780 "}\n";
781
782 const std::string fsSource =
783 "#version 300 es\n"
784 "#extension GL_OVR_multiview2 : require\n"
785 "precision mediump float;\n"
786 "out vec4 col;\n"
787 "void main()\n"
788 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300789 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300790 "}\n";
791
Martin Radev3c25ad02017-08-22 17:36:53 +0300792 createFBO(4, 1, 4);
Martin Radev8f276e22017-05-30 12:05:52 +0300793 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
794 glUseProgram(program);
795
796 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
797 ASSERT_GL_NO_ERROR();
798
799 for (int i = 0; i < 4; ++i)
800 {
801 for (int j = 0; j < 4; ++j)
802 {
Martin Radev8f276e22017-05-30 12:05:52 +0300803 if (i == j)
804 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300805 EXPECT_EQ(GLColor::red, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300806 }
807 else
808 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300809 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300810 }
811 }
812 }
813 EXPECT_GL_NO_ERROR();
814}
815
816// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300817TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +0300818{
819 if (!requestMultiviewExtension())
820 {
821 return;
822 }
823
824 const std::string vsSource =
825 "#version 300 es\n"
826 "#extension GL_OVR_multiview : require\n"
827 "layout(num_views = 2) in;\n"
828 "in vec4 vPosition;\n"
829 "void main()\n"
830 "{\n"
831 " vec4 p = vPosition;\n"
832 " if (gl_InstanceID == 1){\n"
833 " p.y = .5*p.y + .5;\n"
834 " } else {\n"
835 " p.y = p.y*.5;\n"
836 " }\n"
837 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x*0.5 + 0.5 : p.x*0.5);\n"
838 " gl_Position.yzw = p.yzw;\n"
839 "}\n";
840
841 const std::string fsSource =
842 "#version 300 es\n"
843 "#extension GL_OVR_multiview : require\n"
844 "precision mediump float;\n"
845 "out vec4 col;\n"
846 "void main()\n"
847 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300848 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300849 "}\n";
850
Martin Radev3c25ad02017-08-22 17:36:53 +0300851 const int kViewWidth = 2;
852 const int kViewHeight = 2;
853 const int kNumViews = 2;
854 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev8f276e22017-05-30 12:05:52 +0300855 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
856 glUseProgram(program);
857
858 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 2);
859 ASSERT_GL_NO_ERROR();
860
Martin Radev3c25ad02017-08-22 17:36:53 +0300861 const GLubyte expectedRedChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
862 {{255, 0}, {255, 0}}};
863
864 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +0300865 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300866 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +0300867 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300868 for (int x = 0; x < 2; ++x)
869 {
870 EXPECT_EQ(GLColor(expectedRedChannel[view][y][x], 0, 0, 255),
871 GetViewColor(x, y, view));
872 }
Martin Radev8f276e22017-05-30 12:05:52 +0300873 }
874 }
875}
876
Martin Radev553590a2017-07-31 16:40:39 +0300877// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
878// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
879// offset of each quad are passed as separate attributes which are indexed based on the
880// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
881// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
882// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
883// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +0300884TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +0300885{
886 if (!requestMultiviewExtension())
887 {
888 return;
889 }
890
891 const std::string &vsSource =
892 "#version 300 es\n"
893 "#extension GL_OVR_multiview2 : require\n"
894 "layout(num_views = 2) in;\n"
895 "in vec3 vPosition;\n"
896 "in float offsetX;\n"
897 "in float offsetY;\n"
898 "void main()\n"
899 "{\n"
900 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +0300901 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300902 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
903 " gl_Position.yzw = p.yzw;\n"
904 "}\n";
905
906 const std::string &fsSource =
907 "#version 300 es\n"
908 "#extension GL_OVR_multiview2 : require\n"
909 "precision mediump float;\n"
910 "out vec4 col;\n"
911 "void main()\n"
912 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300913 " col = vec4(1,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300914 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +0300915
916 const int kViewWidth = 4;
917 const int kViewHeight = 4;
918 const int kNumViews = 2;
919 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev553590a2017-07-31 16:40:39 +0300920 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
921 glUseProgram(program);
922
923 GLBuffer xOffsetVBO;
924 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
925 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
926 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
927 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
928 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
929 glVertexAttribDivisor(xOffsetLoc, 3);
930 glEnableVertexAttribArray(xOffsetLoc);
931
932 GLBuffer yOffsetVBO;
933 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
934 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
935 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
936 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
937 glVertexAttribDivisor(yOffsetLoc, 1);
938 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
939 glEnableVertexAttribArray(yOffsetLoc);
940
941 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
942 ASSERT_GL_NO_ERROR();
943
Martin Radev3c25ad02017-08-22 17:36:53 +0300944 const GLubyte expectedRedChannel[kNumViews][kViewHeight][kViewWidth] = {
945 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
946 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
947 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +0300948 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300949 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +0300950 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300951 for (int col = 0; col < 4; ++col)
952 {
953 EXPECT_EQ(GLColor(expectedRedChannel[view][row][col], 0, 0, 255),
954 GetViewColor(col, row, view));
955 }
Martin Radev553590a2017-07-31 16:40:39 +0300956 }
957 }
958}
959
960// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
961// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +0300962TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +0300963{
964 if (!requestMultiviewExtension())
965 {
966 return;
967 }
968
Martin Radev3c25ad02017-08-22 17:36:53 +0300969 createFBO(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +0300970
971 // Create multiview program.
972 const std::string &vs =
973 "#version 300 es\n"
974 "#extension GL_OVR_multiview2 : require\n"
975 "layout(num_views = 2) in;\n"
976 "layout(location = 0) in vec2 vPosition;\n"
977 "layout(location = 1) in float offsetX;\n"
978 "void main()\n"
979 "{\n"
980 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
981 " p.x += offsetX;\n"
982 " gl_Position = p;\n"
983 "}\n";
984
985 const std::string &fs =
986 "#version 300 es\n"
987 "#extension GL_OVR_multiview2 : require\n"
988 "precision mediump float;\n"
989 "out vec4 col;\n"
990 "void main()\n"
991 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300992 " col = vec4(1,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300993 "}\n";
994
995 ANGLE_GL_PROGRAM(program, vs, fs);
996
997 const std::string &dummyVS =
998 "#version 300 es\n"
999 "layout(location = 0) in vec2 vPosition;\n"
1000 "layout(location = 1) in float offsetX;\n"
1001 "void main()\n"
1002 "{\n"
1003 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1004 "}\n";
1005
1006 const std::string &dummyFS =
1007 "#version 300 es\n"
1008 "precision mediump float;\n"
1009 "out vec4 col;\n"
1010 "void main()\n"
1011 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001012 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001013 "}\n";
1014
1015 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
1016
1017 GLBuffer xOffsetVBO;
1018 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1019 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1020 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1021 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1022
1023 GLBuffer vertexVBO;
1024 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1025 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1026 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1027 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1028
1029 GLVertexArray vao[2];
1030 for (size_t i = 0u; i < 2u; ++i)
1031 {
1032 glBindVertexArray(vao[i]);
1033
1034 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1035 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1036 glEnableVertexAttribArray(0);
1037
1038 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1039 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1040 glEnableVertexAttribArray(1);
1041 }
1042 ASSERT_GL_NO_ERROR();
1043
1044 glViewport(0, 0, 1, 1);
1045 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001046 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001047 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001048
1049 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1050 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1051 // bits are cleared.
1052 glUseProgram(dummyProgram);
1053 glBindVertexArray(vao[0]);
1054 glVertexAttribDivisor(1, 0);
1055 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1056 glUseProgram(0);
1057 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1058 ASSERT_GL_NO_ERROR();
1059
1060 // Check that vertexAttribDivisor uses the number of views to update the divisor.
1061 glUseProgram(program);
1062 glVertexAttribDivisor(1, 1);
1063 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001064 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1065 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001066
1067 // Clear the buffers and propagate divisor to the driver.
1068 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1069 // dirty bits when useProgram is called.
1070 glUseProgram(dummyProgram);
1071 glVertexAttribDivisor(1, 1);
1072 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1073 glUseProgram(0);
1074 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1075 ASSERT_GL_NO_ERROR();
1076
1077 // Check that useProgram uses the number of views to update the divisor.
1078 glUseProgram(program);
1079 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001080 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1081 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001082
1083 // We go through similar steps as before.
1084 glUseProgram(dummyProgram);
1085 glVertexAttribDivisor(1, 1);
1086 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1087 glUseProgram(0);
1088 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1089 ASSERT_GL_NO_ERROR();
1090
1091 // Check that bindVertexArray uses the number of views to update the divisor.
1092 {
1093 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1094 // divisor for vao[1] only.
1095 glBindVertexArray(vao[1]);
1096 glUseProgram(program);
1097 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1098 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1099 glBindVertexArray(0);
1100 ASSERT_GL_NO_ERROR();
1101 }
1102 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1103 // adjusts the divisor.
1104 glBindVertexArray(vao[0]);
1105 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001106 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1107 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001108}
1109
Martin Radev0d671c92017-08-10 16:41:52 +03001110// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1111// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001112TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001113{
1114 if (!requestMultiviewExtension())
1115 {
1116 return;
1117 }
1118
1119 const std::string vsSource =
1120 "#version 300 es\n"
1121 "#extension GL_OVR_multiview : require\n"
1122 "layout(num_views = 2) in;\n"
1123 "in vec3 vPosition;\n"
1124 "void main()\n"
1125 "{\n"
1126 " gl_Position.x = 2.0;\n"
1127 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1128 "}\n";
1129
1130 const std::string fsSource =
1131 "#version 300 es\n"
1132 "#extension GL_OVR_multiview : require\n"
1133 "precision mediump float;\n"
1134 "out vec4 col;\n"
1135 "void main()\n"
1136 "{\n"
1137 " col = vec4(1,0,0,0);\n"
1138 "}\n";
1139 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1140 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001141 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001142
1143 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1144 ASSERT_GL_NO_ERROR();
1145 EXPECT_GL_FALSE(result);
1146}
1147
1148// Test that there are fragments passing the occlusion query if only view 0 can produce
1149// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001150TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001151{
1152 if (!requestMultiviewExtension())
1153 {
1154 return;
1155 }
1156
1157 const std::string vsSource =
1158 "#version 300 es\n"
1159 "#extension GL_OVR_multiview : require\n"
1160 "layout(num_views = 2) in;\n"
1161 "in vec3 vPosition;\n"
1162 "void main()\n"
1163 "{\n"
1164 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1165 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1166 "}\n";
1167
1168 const std::string fsSource =
1169 "#version 300 es\n"
1170 "#extension GL_OVR_multiview : require\n"
1171 "precision mediump float;\n"
1172 "out vec4 col;\n"
1173 "void main()\n"
1174 "{\n"
1175 " col = vec4(1,0,0,0);\n"
1176 "}\n";
1177 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1178 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001179 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001180
1181 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1182 ASSERT_GL_NO_ERROR();
1183 EXPECT_GL_TRUE(result);
1184}
1185
1186// Test that there are fragments passing the occlusion query if only view 1 can produce
1187// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001188TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001189{
1190 if (!requestMultiviewExtension())
1191 {
1192 return;
1193 }
1194
1195 const std::string vsSource =
1196 "#version 300 es\n"
1197 "#extension GL_OVR_multiview : require\n"
1198 "layout(num_views = 2) in;\n"
1199 "in vec3 vPosition;\n"
1200 "void main()\n"
1201 "{\n"
1202 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1203 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1204 "}\n";
1205
1206 const std::string fsSource =
1207 "#version 300 es\n"
1208 "#extension GL_OVR_multiview : require\n"
1209 "precision mediump float;\n"
1210 "out vec4 col;\n"
1211 "void main()\n"
1212 "{\n"
1213 " col = vec4(1,0,0,0);\n"
1214 "}\n";
1215 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1216 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001217 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001218
1219 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1220 ASSERT_GL_NO_ERROR();
1221 EXPECT_GL_TRUE(result);
1222}
1223
Martin Radev41ac68e2017-06-06 12:16:58 +03001224// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1225// compiles and links without an error.
1226TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1227{
1228 if (!requestMultiviewExtension())
1229 {
1230 return;
1231 }
1232
1233 const std::string vsSource =
1234 "#version 300 es\n"
1235 "#extension GL_OVR_multiview : require\n"
1236 "layout(num_views = 2) in;\n"
1237 "void main()\n"
1238 "{\n"
1239 "}\n";
1240
1241 const std::string fsSource =
1242 "#version 300 es\n"
1243 "#extension GL_OVR_multiview : require\n"
1244 "precision mediump float;\n"
1245 "void main()\n"
1246 "{\n"
1247 "}\n";
1248
1249 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1250 glUseProgram(program);
1251
1252 EXPECT_GL_NO_ERROR();
1253}
1254
1255// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1256// without an error.
1257TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1258{
1259 if (!requestMultiviewExtension())
1260 {
1261 return;
1262 }
1263
1264 const std::string vsSource =
1265 "#version 300 es\n"
1266 "#extension GL_OVR_multiview2 : require\n"
1267 "layout(num_views = 2) in;\n"
1268 "void main()\n"
1269 "{\n"
1270 " if (gl_ViewID_OVR == 0u) {\n"
1271 " gl_Position = vec4(1,0,0,1);\n"
1272 " } else {\n"
1273 " gl_Position = vec4(-1,0,0,1);\n"
1274 " }\n"
1275 "}\n";
1276
1277 const std::string fsSource =
1278 "#version 300 es\n"
1279 "#extension GL_OVR_multiview2 : require\n"
1280 "precision mediump float;\n"
1281 "void main()\n"
1282 "{\n"
1283 "}\n";
1284
1285 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1286 glUseProgram(program);
1287
1288 EXPECT_GL_NO_ERROR();
1289}
1290
1291// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1292// without an error.
1293TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1294{
1295 if (!requestMultiviewExtension())
1296 {
1297 return;
1298 }
1299
1300 const std::string vsSource =
1301 "#version 300 es\n"
1302 "#extension GL_OVR_multiview2 : require\n"
1303 "layout(num_views = 2) in;\n"
1304 "void main()\n"
1305 "{\n"
1306 "}\n";
1307
1308 const std::string fsSource =
1309 "#version 300 es\n"
1310 "#extension GL_OVR_multiview2 : require\n"
1311 "precision mediump float;\n"
1312 "out vec4 col;\n"
1313 "void main()\n"
1314 "{\n"
1315 " if (gl_ViewID_OVR == 0u) {\n"
1316 " col = vec4(1,0,0,1);\n"
1317 " } else {\n"
1318 " col = vec4(-1,0,0,1);\n"
1319 " }\n"
1320 "}\n";
1321
1322 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1323 glUseProgram(program);
1324
1325 EXPECT_GL_NO_ERROR();
1326}
1327
Martin Radev61bd9992017-08-11 13:10:55 +03001328// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001329TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001330{
1331 if (!requestMultiviewExtension())
1332 {
1333 return;
1334 }
1335
1336 const std::string vsSource =
1337 "#version 300 es\n"
1338 "#extension GL_OVR_multiview : require\n"
1339 "layout(num_views = 2) in;\n"
1340 "layout(location=0) in vec2 vPosition;\n"
1341 "void main()\n"
1342 "{\n"
1343 " gl_PointSize = 1.0;\n"
1344 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1345 "}\n";
1346
1347 const std::string fsSource =
1348 "#version 300 es\n"
1349 "#extension GL_OVR_multiview : require\n"
1350 "precision mediump float;\n"
1351 "out vec4 col;\n"
1352 "void main()\n"
1353 "{\n"
1354 " col = vec4(1,0,0,1);\n"
1355 "}\n";
1356 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1357 glUseProgram(program);
1358
Martin Radev3c25ad02017-08-22 17:36:53 +03001359 const int kViewWidth = 4;
1360 const int kViewHeight = 2;
1361 const int kNumViews = 2;
1362 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001363
1364 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1365 std::vector<Vector2> vertexDataInClipSpace =
1366 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1367 setupGeometry(vertexDataInClipSpace);
1368
1369 glDrawArrays(GL_POINTS, 0, 2);
1370
Martin Radev3c25ad02017-08-22 17:36:53 +03001371 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1372 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
1373 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001374}
1375
1376// The test checks that GL_LINES is correctly rendered.
1377// The behavior of this test is not guaranteed by the spec:
1378// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1379// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1380// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1381// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001382TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001383{
1384 if (!requestMultiviewExtension())
1385 {
1386 return;
1387 }
1388
Martin Radevced5c862017-08-17 16:05:29 +03001389 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001390 ASSERT_NE(program, 0u);
1391 glUseProgram(program);
1392 ASSERT_GL_NO_ERROR();
1393
Martin Radev3c25ad02017-08-22 17:36:53 +03001394 const int kViewWidth = 4;
1395 const int kViewHeight = 2;
1396 const int kNumViews = 2;
1397 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001398
1399 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1400 std::vector<Vector2> vertexDataInClipSpace =
1401 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1402 setupGeometry(vertexDataInClipSpace);
1403
1404 glDrawArrays(GL_LINES, 0, 2);
1405
Martin Radev3c25ad02017-08-22 17:36:53 +03001406 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1407 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
1408 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001409
1410 glDeleteProgram(program);
1411}
1412
1413// The test checks that GL_LINE_STRIP is correctly rendered.
1414// The behavior of this test is not guaranteed by the spec:
1415// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1416// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1417// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1418// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001419TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001420{
1421 if (!requestMultiviewExtension())
1422 {
1423 return;
1424 }
1425
Martin Radevced5c862017-08-17 16:05:29 +03001426 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001427 ASSERT_NE(program, 0u);
1428 glUseProgram(program);
1429 ASSERT_GL_NO_ERROR();
1430
Martin Radev3c25ad02017-08-22 17:36:53 +03001431 const int kViewWidth = 4;
1432 const int kViewHeight = 2;
1433 const int kNumViews = 2;
1434 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001435
1436 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1437 std::vector<Vector2> vertexDataInClipSpace =
1438 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1439 setupGeometry(vertexDataInClipSpace);
1440
1441 glDrawArrays(GL_LINE_STRIP, 0, 3);
1442
Martin Radev3c25ad02017-08-22 17:36:53 +03001443 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1444 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
1445 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001446
1447 glDeleteProgram(program);
1448}
1449
1450// The test checks that GL_LINE_LOOP is correctly rendered.
1451// The behavior of this test is not guaranteed by the spec:
1452// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1453// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1454// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1455// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001456TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001457{
1458 if (!requestMultiviewExtension())
1459 {
1460 return;
1461 }
1462
Martin Radevced5c862017-08-17 16:05:29 +03001463 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001464 ASSERT_NE(program, 0u);
1465 glUseProgram(program);
1466 ASSERT_GL_NO_ERROR();
1467
Martin Radev3c25ad02017-08-22 17:36:53 +03001468 const int kViewWidth = 4;
1469 const int kViewHeight = 4;
1470 const int kNumViews = 2;
1471 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001472
1473 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1474 Vector2I(0, 3)};
1475 std::vector<Vector2> vertexDataInClipSpace =
1476 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1477 setupGeometry(vertexDataInClipSpace);
1478
1479 glDrawArrays(GL_LINE_LOOP, 0, 4);
1480
Martin Radev3c25ad02017-08-22 17:36:53 +03001481 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1482 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1483 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
1484 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001485
1486 glDeleteProgram(program);
1487}
1488
1489// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001490TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001491{
1492 if (!requestMultiviewExtension())
1493 {
1494 return;
1495 }
1496
Martin Radevced5c862017-08-17 16:05:29 +03001497 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001498 ASSERT_NE(program, 0u);
1499 glUseProgram(program);
1500 ASSERT_GL_NO_ERROR();
1501
1502 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1503 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1504 setupGeometry(vertexDataInClipSpace);
1505
Martin Radev3c25ad02017-08-22 17:36:53 +03001506 const int kViewWidth = 2;
1507 const int kViewHeight = 2;
1508 const int kNumViews = 2;
1509 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001510
1511 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1512
Martin Radev3c25ad02017-08-22 17:36:53 +03001513 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {{{0, 0}, {0, 255}},
1514 {{0, 0}, {0, 255}}};
1515 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001516
1517 glDeleteProgram(program);
1518}
1519
1520// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001521TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001522{
1523 if (!requestMultiviewExtension())
1524 {
1525 return;
1526 }
1527
Martin Radevced5c862017-08-17 16:05:29 +03001528 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001529 ASSERT_NE(program, 0u);
1530 glUseProgram(program);
1531 ASSERT_GL_NO_ERROR();
1532
1533 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1534 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1535 setupGeometry(vertexDataInClipSpace);
1536
Martin Radev3c25ad02017-08-22 17:36:53 +03001537 const int kViewWidth = 2;
1538 const int kViewHeight = 2;
1539 const int kNumViews = 2;
1540 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001541
1542 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1543
Martin Radev3c25ad02017-08-22 17:36:53 +03001544 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {{{0, 0}, {0, 255}},
1545 {{0, 0}, {0, 255}}};
1546 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001547
1548 glDeleteProgram(program);
1549}
1550
1551// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1552// bounds. The test does not rely on the actual line width being greater than 1.0.
Martin Radev3c25ad02017-08-22 17:36:53 +03001553TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
Martin Radev61bd9992017-08-11 13:10:55 +03001554{
1555 if (!requestMultiviewExtension())
1556 {
1557 return;
1558 }
1559
Martin Radev3c25ad02017-08-22 17:36:53 +03001560 createFBO(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +03001561
1562 GLint viewportOffsets[4] = {1, 0, 3, 0};
1563 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1564 mColorTexture, 0, 2, &viewportOffsets[0]);
1565 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
1566 mDepthTexture, 0, 2, &viewportOffsets[0]);
1567
1568 glViewport(0, 0, 1, 1);
1569 glScissor(0, 0, 1, 1);
1570 glEnable(GL_SCISSOR_TEST);
1571
1572 const std::string vsSource =
1573 "#version 300 es\n"
1574 "#extension GL_OVR_multiview2 : require\n"
1575 "layout(num_views = 2) in;\n"
1576 "layout(location=0) in vec2 vPosition;\n"
1577 "void main()\n"
1578 "{\n"
1579 " gl_PointSize = 10.0;\n"
1580 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1581 "}\n";
1582
1583 const std::string fsSource =
1584 "#version 300 es\n"
1585 "#extension GL_OVR_multiview2 : require\n"
1586 "precision mediump float;\n"
1587 "out vec4 col;\n"
1588 "void main()\n"
1589 "{\n"
1590 " if (gl_ViewID_OVR == 0u) {\n"
1591 " col = vec4(1,0,0,1);\n"
1592 " } else {\n"
1593 " col = vec4(0,1,0,1);\n"
1594 " }\n"
1595 "}\n";
1596 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1597 glUseProgram(program);
1598
1599 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1600 const std::vector<Vector2> &vertexDataInClipSpace =
1601 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001602
1603 GLBuffer vbo;
1604 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1605 glBufferData(GL_ARRAY_BUFFER, vertexDataInClipSpace.size() * sizeof(Vector2),
1606 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1607 glEnableVertexAttribArray(0);
1608 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
Martin Radev61bd9992017-08-11 13:10:55 +03001609
1610 // Test rendering points.
1611 {
1612 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1613 glDrawArrays(GL_POINTS, 0, 2);
1614 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1615 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1616 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1617 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1618 }
1619
1620 // Test rendering lines.
1621 {
1622 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1623 glLineWidth(10.f);
1624 glDrawArrays(GL_LINES, 0, 2);
1625 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1626 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1627 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1628 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1629 }
1630}
1631
Martin Radev0abb7a22017-08-28 15:34:45 +03001632// Verify that re-linking a program adjusts the attribute divisor.
1633// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1634// to each other. The quads' position and color depend on the corresponding attribute divisors.
1635TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1636{
1637 if (!requestMultiviewExtension())
1638 {
1639 return;
1640 }
1641
1642 const int kViewWidth = 4;
1643 const int kViewHeight = 1;
1644 const int kNumViews = 2;
1645
1646 const std::string &fsSource =
1647 "#version 300 es\n"
1648 "#extension GL_OVR_multiview2 : require\n"
1649 "precision mediump float;\n"
1650 "in vec4 oColor;\n"
1651 "out vec4 col;\n"
1652 "void main()\n"
1653 "{\n"
1654 " col = oColor;\n"
1655 "}\n";
1656
1657 auto generateVertexShaderSource = [](int numViews) -> std::string {
1658 std::string source =
1659 "#version 300 es\n"
1660 "#extension GL_OVR_multiview2 : require\n"
1661 "layout(num_views = " +
1662 ToString(numViews) +
1663 ") in;\n"
1664 "in vec3 vPosition;\n"
1665 "in float vOffsetX;\n"
1666 "in vec4 vColor;\n"
1667 "out vec4 oColor;\n"
1668 "void main()\n"
1669 "{\n"
1670 " vec4 p = vec4(vPosition, 1.);\n"
1671 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1672 " oColor = vColor;\n"
1673 " gl_Position = p;\n"
1674 "}\n";
1675 return source;
1676 };
1677
1678 std::string vsSource = generateVertexShaderSource(kNumViews);
1679 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1680 glUseProgram(program);
1681
1682 GLint positionLoc;
1683 GLBuffer xOffsetVBO;
1684 GLint xOffsetLoc;
1685 GLBuffer colorVBO;
1686 GLint colorLoc;
1687
1688 {
1689 // Initialize buffers and setup attributes.
1690 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1691 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1692 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1693 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1694 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1695 glVertexAttribDivisor(xOffsetLoc, 1);
1696 glEnableVertexAttribArray(xOffsetLoc);
1697
1698 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1699 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1700 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1701 colorLoc = glGetAttribLocation(program, "vColor");
1702 glVertexAttribDivisor(colorLoc, 2);
1703 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1704 glEnableVertexAttribArray(colorLoc);
1705
1706 positionLoc = glGetAttribLocation(program, "vPosition");
1707 }
1708
1709 {
1710 createFBO(kViewWidth, kViewHeight, kNumViews);
1711
1712 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
1713 ASSERT_GL_NO_ERROR();
1714
1715 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1716 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1717 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1718 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1719 }
1720
1721 {
1722 const int kNewNumViews = 3;
1723 vsSource = generateVertexShaderSource(kNewNumViews);
1724 createFBO(kViewWidth, kViewHeight, kNewNumViews);
1725
1726 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
1727 ASSERT_NE(0u, vs);
1728 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
1729 ASSERT_NE(0u, fs);
1730
1731 GLint numAttachedShaders = 0;
1732 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1733
1734 GLuint attachedShaders[2] = {0u};
1735 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1736 for (int i = 0; i < 2; ++i)
1737 {
1738 glDetachShader(program, attachedShaders[i]);
1739 }
1740
1741 glAttachShader(program, vs);
1742 glDeleteShader(vs);
1743
1744 glAttachShader(program, fs);
1745 glDeleteShader(fs);
1746
1747 glBindAttribLocation(program, positionLoc, "vPosition");
1748 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1749 glBindAttribLocation(program, colorLoc, "vColor");
1750
1751 glLinkProgram(program);
1752
1753 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
1754 ASSERT_GL_NO_ERROR();
1755
1756 for (int i = 0; i < kNewNumViews; ++i)
1757 {
1758 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1759 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1760 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1761 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1762 }
1763 }
1764}
1765
Martin Radevced5c862017-08-17 16:05:29 +03001766// Test that useProgram applies the number of views in computing the final value of the attribute
1767// divisor.
1768TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1769{
1770 if (!requestMultiviewExtension())
1771 {
1772 return;
1773 }
1774
1775 GLVertexArray vao;
1776 glBindVertexArray(vao);
1777 GLBuffer vbo;
1778 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1779 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
1780 Vector2I(3, 0)};
1781 std::vector<Vector2> vertexDataInClipSpace =
1782 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
1783 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
1784 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
1785 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1786 glEnableVertexAttribArray(0);
1787 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
1788 glVertexAttribDivisor(0, 1);
1789 ASSERT_GL_NO_ERROR();
1790
1791 // Create a program and fbo with N views and draw N instances of a point horizontally.
1792 for (int numViews = 2; numViews <= 4; ++numViews)
1793 {
1794 createFBO(4, 1, numViews);
1795 ASSERT_GL_NO_ERROR();
1796
1797 GLuint program = CreateSimplePassthroughProgram(numViews);
1798 ASSERT_NE(program, 0u);
1799 glUseProgram(program);
1800 ASSERT_GL_NO_ERROR();
1801
1802 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
1803
1804 for (int view = 0; view < numViews; ++view)
1805 {
1806 for (int j = 0; j < numViews; ++j)
1807 {
1808 EXPECT_EQ(GLColor::red, GetViewColor(j, 0, view));
1809 }
1810 for (int j = numViews; j < 4; ++j)
1811 {
1812 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, view));
1813 }
1814 }
1815
1816 glDeleteProgram(program);
1817 }
1818}
1819
Martin Radev3c25ad02017-08-22 17:36:53 +03001820MultiviewTestParams SideBySideOpenGL()
1821{
1822 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, egl_platform::OPENGL());
1823}
1824
1825MultiviewTestParams LayeredOpenGL()
1826{
1827 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, egl_platform::OPENGL());
1828}
1829
1830MultiviewTestParams SideBySideD3D11()
1831{
1832 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, egl_platform::D3D11());
1833}
1834
Martin Radev8f276e22017-05-30 12:05:52 +03001835ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest, ES31_OPENGL());
Martin Radevced5c862017-08-17 16:05:29 +03001836ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
1837 SideBySideOpenGL(),
1838 LayeredOpenGL(),
1839 SideBySideD3D11());
1840ANGLE_INSTANTIATE_TEST(MultiviewRenderTest, SideBySideOpenGL(), LayeredOpenGL(), SideBySideD3D11());
1841ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
1842 SideBySideOpenGL(),
1843 LayeredOpenGL(),
1844 SideBySideD3D11());
Martin Radev3c25ad02017-08-22 17:36:53 +03001845ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest, SideBySideOpenGL(), SideBySideD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03001846ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
1847 SideBySideOpenGL(),
1848 LayeredOpenGL(),
1849 SideBySideD3D11());