blob: cb2aa77c24af3057c0bae45f0ba628ec30ae3107 [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
179 // Create color and depth textures.
Martin Radev3c25ad02017-08-22 17:36:53 +0300180 switch (mMultiviewLayout)
Martin Radev8f276e22017-05-30 12:05:52 +0300181 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300182 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
183 {
184 int textureWidth = viewWidth * numViews;
185 glBindTexture(GL_TEXTURE_2D, mColorTexture);
186 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, height, 0, GL_RGBA,
187 GL_UNSIGNED_BYTE, NULL);
188 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
189 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
190
191 glBindTexture(GL_TEXTURE_2D, mDepthTexture);
192 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, textureWidth, height, 0,
193 GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
194 glBindTexture(GL_TEXTURE_2D, 0);
195 break;
196 }
197 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
198 glBindTexture(GL_TEXTURE_2D_ARRAY, mColorTexture);
199 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, viewWidth, height, numViews, 0,
200 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
201 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
202 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
203
204 glBindTexture(GL_TEXTURE_2D_ARRAY, mDepthTexture);
205 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, viewWidth, height,
206 numViews, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
207 glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
208 break;
209 default:
210 UNREACHABLE();
Martin Radev8f276e22017-05-30 12:05:52 +0300211 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300212 ASSERT_GL_NO_ERROR();
213
214 // Create draw framebuffer to be used for multiview rendering.
215 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
216 switch (mMultiviewLayout)
217 {
218 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
219 {
220 std::vector<GLint> viewportOffsets(numViews * 2);
221 for (int i = 0u; i < numViews; ++i)
222 {
223 viewportOffsets[i * 2] = i * viewWidth;
224 viewportOffsets[i * 2 + 1] = 0;
225 }
226 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER,
227 GL_COLOR_ATTACHMENT0, mColorTexture, 0,
228 numViews, &viewportOffsets[0]);
229 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER,
230 GL_DEPTH_ATTACHMENT, mDepthTexture, 0,
231 numViews, &viewportOffsets[0]);
232 break;
233 }
234 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
235 glFramebufferTextureMultiviewLayeredANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
236 mColorTexture, 0, 0, numViews);
237 glFramebufferTextureMultiviewLayeredANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
238 mDepthTexture, 0, 0, numViews);
239 break;
240 default:
241 UNREACHABLE();
242 }
Martin Radev8f276e22017-05-30 12:05:52 +0300243
244 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
245 glDrawBuffers(1, DrawBuffers);
246 ASSERT_GL_NO_ERROR();
247 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
248
249 // Create read framebuffer to be used to retrieve the pixel information for testing
250 // purposes.
Martin Radev3c25ad02017-08-22 17:36:53 +0300251 switch (mMultiviewLayout)
252 {
253 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
254 mReadFramebuffer.resize(1);
255 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
256 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
257 mColorTexture, 0);
258 break;
259 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
260 mReadFramebuffer.resize(numViews);
261 for (int i = 0; i < numViews; ++i)
262 {
263 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
264 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
265 mColorTexture, 0, i);
266 }
267 break;
268 default:
269 UNREACHABLE();
270 }
Martin Radev8f276e22017-05-30 12:05:52 +0300271 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
272
273 // Clear the buffers.
Martin Radev3c25ad02017-08-22 17:36:53 +0300274 glViewport(0, 0, viewWidth, height);
275 if (mMultiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
276 {
277 // Enable the scissor test only for side-by-side framebuffers.
278 glEnable(GL_SCISSOR_TEST);
279 glScissor(0, 0, viewWidth, height);
280 }
Martin Radev61bd9992017-08-11 13:10:55 +0300281 glClearColor(0, 0, 0, 1);
Martin Radev8f276e22017-05-30 12:05:52 +0300282 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev3c25ad02017-08-22 17:36:53 +0300283 }
Martin Radev8f276e22017-05-30 12:05:52 +0300284
Martin Radev3c25ad02017-08-22 17:36:53 +0300285 GLColor GetViewColor(int x, int y, int view)
286 {
287 switch (mMultiviewLayout)
288 {
289 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
290 return ReadColor(view * mViewWidth + x, y);
291 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
292 ASSERT(static_cast<size_t>(view) < mReadFramebuffer.size());
293 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
294 return ReadColor(x, y);
295 default:
296 UNREACHABLE();
297 }
298 return GLColor(0, 0, 0, 0);
Martin Radev8f276e22017-05-30 12:05:52 +0300299 }
300
301 GLTexture mColorTexture;
302 GLTexture mDepthTexture;
303 GLFramebuffer mDrawFramebuffer;
Martin Radev3c25ad02017-08-22 17:36:53 +0300304 std::vector<GLFramebuffer> mReadFramebuffer;
305 GLenum mMultiviewLayout;
306 int mViewWidth;
307 int mViewHeight;
308 int mNumViews;
Martin Radev8f276e22017-05-30 12:05:52 +0300309};
310
Martin Radev3c25ad02017-08-22 17:36:53 +0300311class MultiviewRenderTest : public MultiviewRenderTestBase,
312 public ::testing::TestWithParam<MultiviewTestParams>
Martin Radev8f276e22017-05-30 12:05:52 +0300313{
314 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300315 MultiviewRenderTest() : MultiviewRenderTestBase(GetParam(), GetParam().mMultiviewLayout) {}
316 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
317};
318
319class MultiviewRenderDualViewTest : public MultiviewRenderTest
320{
321 protected:
322 MultiviewRenderDualViewTest() : mProgram(0u) {}
323 ~MultiviewRenderDualViewTest()
Martin Radev8f276e22017-05-30 12:05:52 +0300324 {
325 if (mProgram != 0u)
326 {
327 glDeleteProgram(mProgram);
328 }
329 }
330
331 void SetUp() override
332 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300333 MultiviewRenderTest::SetUp();
Martin Radev8f276e22017-05-30 12:05:52 +0300334
335 if (!requestMultiviewExtension())
336 {
337 return;
338 }
339
340 const std::string vsSource =
341 "#version 300 es\n"
342 "#extension GL_OVR_multiview : require\n"
343 "layout(num_views = 2) in;\n"
344 "in vec4 vPosition;\n"
345 "void main()\n"
346 "{\n"
347 " gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x*0.5 + 0.5 : vPosition.x*0.5);\n"
348 " gl_Position.yzw = vPosition.yzw;\n"
349 "}\n";
350
351 const std::string fsSource =
352 "#version 300 es\n"
353 "#extension GL_OVR_multiview : require\n"
354 "precision mediump float;\n"
355 "out vec4 col;\n"
356 "void main()\n"
357 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300358 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300359 "}\n";
360
Martin Radev3c25ad02017-08-22 17:36:53 +0300361 createFBO(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +0300362 mProgram = CompileProgram(vsSource, fsSource);
363 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300364 glUseProgram(mProgram);
365 ASSERT_GL_NO_ERROR();
366 }
367
368 void checkOutput()
369 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300370 EXPECT_EQ(GLColor::black, GetViewColor(0, 0, 0));
371 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
372 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
373 EXPECT_EQ(GLColor::black, GetViewColor(1, 0, 1));
Martin Radev8f276e22017-05-30 12:05:52 +0300374 }
375
376 GLuint mProgram;
377};
378
Martin Radev3c25ad02017-08-22 17:36:53 +0300379class MultiviewOcclusionQueryTest : public MultiviewRenderTest
Martin Radev0d671c92017-08-10 16:41:52 +0300380{
381 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300382 MultiviewOcclusionQueryTest() {}
Martin Radev0d671c92017-08-10 16:41:52 +0300383
384 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
385 {
386 GLuint query;
387 glGenQueries(1, &query);
388 glBeginQuery(GL_ANY_SAMPLES_PASSED, query);
389 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
390 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
391
392 GLuint result = GL_TRUE;
393 glGetQueryObjectuiv(query, GL_QUERY_RESULT, &result);
394 return result;
395 }
396};
397
Martin Radev3c25ad02017-08-22 17:36:53 +0300398class MultiviewProgramGenerationTest : public MultiviewRenderTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300399{
400 protected:
401 MultiviewProgramGenerationTest() {}
402};
403
Martin Radev3c25ad02017-08-22 17:36:53 +0300404class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300405{
406 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300407 MultiviewRenderPrimitiveTest() {}
Martin Radev61bd9992017-08-11 13:10:55 +0300408
409 void setupGeometry(const std::vector<Vector2> &vertexData)
410 {
Martin Radev61bd9992017-08-11 13:10:55 +0300411 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
412 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
413 GL_STATIC_DRAW);
414 glEnableVertexAttribArray(0);
415 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
416 }
417
Martin Radev3c25ad02017-08-22 17:36:53 +0300418 void checkRedChannel(const GLubyte expectedRedChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300419 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300420 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300421 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300422 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300423 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300424 for (int h = 0; h < mViewHeight; ++h)
425 {
426 size_t flatIndex =
427 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
428 EXPECT_EQ(GLColor(expectedRedChannelData[flatIndex], 0, 0, 255),
429 GetViewColor(w, h, view));
430 }
Martin Radev61bd9992017-08-11 13:10:55 +0300431 }
432 }
433 }
Martin Radev61bd9992017-08-11 13:10:55 +0300434 GLBuffer mVBO;
435};
436
Martin Radev3c25ad02017-08-22 17:36:53 +0300437class MultiviewSideBySideRenderTest : public MultiviewRenderTestBase,
438 public ::testing::TestWithParam<PlatformParameters>
439{
440 protected:
441 MultiviewSideBySideRenderTest()
442 : MultiviewRenderTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
443 {
444 }
445 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
446};
447
Martin Radev14a26ae2017-07-24 15:56:29 +0300448// The test verifies that glDraw*Indirect:
449// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
450// than 1.
451// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +0300452TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300453{
454 if (!requestMultiviewExtension())
455 {
456 return;
457 }
458
Martin Radev14a26ae2017-07-24 15:56:29 +0300459 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +0300460
461 const std::string fsSource =
462 "#version 300 es\n"
463 "#extension GL_OVR_multiview : require\n"
464 "precision mediump float;\n"
465 "void main()\n"
466 "{}\n";
467
Martin Radev14a26ae2017-07-24 15:56:29 +0300468 GLBuffer commandBuffer;
469 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
470 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
471 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
472 ASSERT_GL_NO_ERROR();
473
Martin Radev14a26ae2017-07-24 15:56:29 +0300474 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
475 {
476 const std::string &vsSource =
477 "#version 300 es\n"
478 "#extension GL_OVR_multiview : require\n"
479 "layout(num_views = 2) in;\n"
480 "void main()\n"
481 "{}\n";
482 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
483 glUseProgram(program);
484
Martin Radev7cf61662017-07-26 17:10:53 +0300485 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
486 0, 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300487
488 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
489 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
490
491 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
492 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
493 }
494
495 // Check that no errors are generated if the number of views is 1.
496 {
497 const std::string &vsSource =
498 "#version 300 es\n"
499 "#extension GL_OVR_multiview : require\n"
500 "layout(num_views = 1) in;\n"
501 "void main()\n"
502 "{}\n";
503 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
504 glUseProgram(program);
505
Martin Radev7cf61662017-07-26 17:10:53 +0300506 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
507 0, 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300508
509 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
510 EXPECT_GL_NO_ERROR();
511
512 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
513 EXPECT_GL_NO_ERROR();
514 }
515}
516
Martin Radev7cf61662017-07-26 17:10:53 +0300517// The test verifies that glDraw*:
518// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
519// program differs.
520// 2) does not generate any error if the number of views is the same.
521// 3) does not generate any error if the program does not use the multiview extension.
522TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
523{
524 if (!requestMultiviewExtension())
525 {
526 return;
527 }
528
529 const GLint viewportOffsets[4] = {0, 0, 2, 0};
530
531 const std::string &vsSource =
532 "#version 300 es\n"
533 "#extension GL_OVR_multiview : require\n"
534 "layout(num_views = 2) in;\n"
535 "void main()\n"
536 "{}\n";
537 const std::string &fsSource =
538 "#version 300 es\n"
539 "#extension GL_OVR_multiview : require\n"
540 "precision mediump float;\n"
541 "void main()\n"
542 "{}\n";
543 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
544 glUseProgram(program);
545
546 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
547 // number of views.
548 {
549 // The framebuffer has only 1 view.
550 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
551 0, 1, &viewportOffsets[0]);
552
553 glDrawArrays(GL_TRIANGLES, 0, 3);
554 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
555
556 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
557 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
558 }
559
560 // Check that no errors are generated if the number of views in both program and draw
561 // framebuffer matches.
562 {
563 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
564 0, 2, &viewportOffsets[0]);
565
566 glDrawArrays(GL_TRIANGLES, 0, 3);
567 EXPECT_GL_NO_ERROR();
568
569 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
570 EXPECT_GL_NO_ERROR();
571 }
572
573 // Check that no errors are generated if the program does not use the multiview extension.
574 {
575 const std::string &vsSourceNoMultiview =
576 "#version 300 es\n"
577 "void main()\n"
578 "{}\n";
579 const std::string &fsSourceNoMultiview =
580 "#version 300 es\n"
581 "precision mediump float;\n"
582 "void main()\n"
583 "{}\n";
584 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
585 glUseProgram(programNoMultiview);
586
587 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
588 0, 2, &viewportOffsets[0]);
589
590 glDrawArrays(GL_TRIANGLES, 0, 3);
591 EXPECT_GL_NO_ERROR();
592
593 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
594 EXPECT_GL_NO_ERROR();
595 }
596}
597
Martin Radev7e69f762017-07-27 14:54:13 +0300598// The test verifies that glDraw*:
599// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
600// greater than 1 and there is an active transform feedback object.
601// 2) does not generate any error if the number of views in the draw framebuffer is 1.
602TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
603{
604 if (!requestMultiviewExtension())
605 {
606 return;
607 }
608
609 const GLint viewportOffsets[4] = {0, 0, 2, 0};
610
611 const std::string &vsSource =
612 "#version 300 es\n"
613 "void main()\n"
614 "{}\n";
615 const std::string &fsSource =
616 "#version 300 es\n"
617 "precision mediump float;\n"
618 "void main()\n"
619 "{}\n";
620 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
621 glUseProgram(program);
622
623 GLBuffer tbo;
624 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
625 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4u, nullptr, GL_STATIC_DRAW);
626
627 GLTransformFeedback transformFeedback;
628 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
629 glBeginTransformFeedback(GL_TRIANGLES);
630 ASSERT_GL_NO_ERROR();
631
632 // Check that drawArrays generates an error when there is an active transform feedback object
633 // and the number of views in the draw framebuffer is greater than 1.
634 {
635 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
636 0, 2, &viewportOffsets[0]);
637 glDrawArrays(GL_TRIANGLES, 0, 3);
638 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
639 }
640
641 // Check that drawArrays does not generate an error when the number of views in the draw
642 // framebuffer is 1.
643 {
644 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
645 0, 1, &viewportOffsets[0]);
646 glDrawArrays(GL_TRIANGLES, 0, 3);
647 EXPECT_GL_NO_ERROR();
648 }
649
650 glEndTransformFeedback();
651}
652
Martin Radevffe754b2017-07-31 10:38:07 +0300653// The test verifies that glDraw*:
654// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
655// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
656// 2) does not generate any error if the number of views in the draw framebuffer is 1.
657TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
658{
659 if (!requestMultiviewExtension())
660 {
661 return;
662 }
663
664 if (!extensionEnabled("GL_EXT_disjoint_timer_query"))
665 {
666 std::cout << "Test skipped because GL_EXT_disjoint_timer_query is not available."
667 << std::endl;
668 return;
669 }
670
671 const GLint viewportOffsets[4] = {0, 0, 2, 0};
672 const std::string &vsSource =
673 "#version 300 es\n"
674 "void main()\n"
675 "{}\n";
676 const std::string &fsSource =
677 "#version 300 es\n"
678 "precision mediump float;\n"
679 "void main()\n"
680 "{}\n";
681 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
682 glUseProgram(program);
683
684 GLuint query = 0u;
685 glGenQueriesEXT(1, &query);
686 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
687
688 // Check first case.
689 {
690 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
691 0, 2, &viewportOffsets[0]);
692 glDrawArrays(GL_TRIANGLES, 0, 3);
693 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
694 }
695
696 // Check second case.
697 {
698 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
699 0, 1, &viewportOffsets[0]);
700 glDrawArrays(GL_TRIANGLES, 0, 3);
701 EXPECT_GL_NO_ERROR();
702 }
703
704 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
705 glDeleteQueries(1, &query);
706}
707
Martin Radev8f276e22017-05-30 12:05:52 +0300708// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300709TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300710{
711 if (!requestMultiviewExtension())
712 {
713 return;
714 }
715 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
716 ASSERT_GL_NO_ERROR();
717
718 checkOutput();
719}
720
721// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300722TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300723{
724 if (!requestMultiviewExtension())
725 {
726 return;
727 }
728 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
729 ASSERT_GL_NO_ERROR();
730
731 checkOutput();
732}
733
734// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300735TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300736{
737 if (!requestMultiviewExtension())
738 {
739 return;
740 }
741 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
742 ASSERT_GL_NO_ERROR();
743
744 checkOutput();
745}
746
747// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300748TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300749{
750 if (!requestMultiviewExtension())
751 {
752 return;
753 }
754
755 const std::string vsSource =
756 "#version 300 es\n"
757 "#extension GL_OVR_multiview2 : require\n"
758 "layout(num_views = 4) in;\n"
759 "in vec4 vPosition;\n"
760 "void main()\n"
761 "{\n"
762 " if (gl_ViewID_OVR == 0u) {\n"
763 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
764 " } else if (gl_ViewID_OVR == 1u) {\n"
765 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
766 " } else if (gl_ViewID_OVR == 2u) {\n"
767 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
768 " } else {\n"
769 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
770 " }"
771 " gl_Position.yzw = vPosition.yzw;\n"
772 "}\n";
773
774 const std::string fsSource =
775 "#version 300 es\n"
776 "#extension GL_OVR_multiview2 : require\n"
777 "precision mediump float;\n"
778 "out vec4 col;\n"
779 "void main()\n"
780 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300781 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300782 "}\n";
783
Martin Radev3c25ad02017-08-22 17:36:53 +0300784 createFBO(4, 1, 4);
Martin Radev8f276e22017-05-30 12:05:52 +0300785 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
786 glUseProgram(program);
787
788 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
789 ASSERT_GL_NO_ERROR();
790
791 for (int i = 0; i < 4; ++i)
792 {
793 for (int j = 0; j < 4; ++j)
794 {
Martin Radev8f276e22017-05-30 12:05:52 +0300795 if (i == j)
796 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300797 EXPECT_EQ(GLColor::red, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300798 }
799 else
800 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300801 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300802 }
803 }
804 }
805 EXPECT_GL_NO_ERROR();
806}
807
808// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300809TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +0300810{
811 if (!requestMultiviewExtension())
812 {
813 return;
814 }
815
816 const std::string vsSource =
817 "#version 300 es\n"
818 "#extension GL_OVR_multiview : require\n"
819 "layout(num_views = 2) in;\n"
820 "in vec4 vPosition;\n"
821 "void main()\n"
822 "{\n"
823 " vec4 p = vPosition;\n"
824 " if (gl_InstanceID == 1){\n"
825 " p.y = .5*p.y + .5;\n"
826 " } else {\n"
827 " p.y = p.y*.5;\n"
828 " }\n"
829 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x*0.5 + 0.5 : p.x*0.5);\n"
830 " gl_Position.yzw = p.yzw;\n"
831 "}\n";
832
833 const std::string fsSource =
834 "#version 300 es\n"
835 "#extension GL_OVR_multiview : require\n"
836 "precision mediump float;\n"
837 "out vec4 col;\n"
838 "void main()\n"
839 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300840 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300841 "}\n";
842
Martin Radev3c25ad02017-08-22 17:36:53 +0300843 const int kViewWidth = 2;
844 const int kViewHeight = 2;
845 const int kNumViews = 2;
846 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev8f276e22017-05-30 12:05:52 +0300847 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
848 glUseProgram(program);
849
850 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 2);
851 ASSERT_GL_NO_ERROR();
852
Martin Radev3c25ad02017-08-22 17:36:53 +0300853 const GLubyte expectedRedChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
854 {{255, 0}, {255, 0}}};
855
856 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +0300857 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300858 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +0300859 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300860 for (int x = 0; x < 2; ++x)
861 {
862 EXPECT_EQ(GLColor(expectedRedChannel[view][y][x], 0, 0, 255),
863 GetViewColor(x, y, view));
864 }
Martin Radev8f276e22017-05-30 12:05:52 +0300865 }
866 }
867}
868
Martin Radev553590a2017-07-31 16:40:39 +0300869// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
870// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
871// offset of each quad are passed as separate attributes which are indexed based on the
872// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
873// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
874// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
875// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +0300876TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +0300877{
878 if (!requestMultiviewExtension())
879 {
880 return;
881 }
882
883 const std::string &vsSource =
884 "#version 300 es\n"
885 "#extension GL_OVR_multiview2 : require\n"
886 "layout(num_views = 2) in;\n"
887 "in vec3 vPosition;\n"
888 "in float offsetX;\n"
889 "in float offsetY;\n"
890 "void main()\n"
891 "{\n"
892 " vec4 p = vec4(vPosition, 1.);\n"
893 " p.xy = p.xy * 0.25 - 0.75 + vec2(offsetX, offsetY);\n"
894 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
895 " gl_Position.yzw = p.yzw;\n"
896 "}\n";
897
898 const std::string &fsSource =
899 "#version 300 es\n"
900 "#extension GL_OVR_multiview2 : require\n"
901 "precision mediump float;\n"
902 "out vec4 col;\n"
903 "void main()\n"
904 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300905 " col = vec4(1,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300906 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +0300907
908 const int kViewWidth = 4;
909 const int kViewHeight = 4;
910 const int kNumViews = 2;
911 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev553590a2017-07-31 16:40:39 +0300912 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
913 glUseProgram(program);
914
915 GLBuffer xOffsetVBO;
916 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
917 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
918 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
919 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
920 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
921 glVertexAttribDivisor(xOffsetLoc, 3);
922 glEnableVertexAttribArray(xOffsetLoc);
923
924 GLBuffer yOffsetVBO;
925 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
926 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
927 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
928 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
929 glVertexAttribDivisor(yOffsetLoc, 1);
930 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
931 glEnableVertexAttribArray(yOffsetLoc);
932
933 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
934 ASSERT_GL_NO_ERROR();
935
Martin Radev3c25ad02017-08-22 17:36:53 +0300936 const GLubyte expectedRedChannel[kNumViews][kViewHeight][kViewWidth] = {
937 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
938 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
939 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +0300940 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300941 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +0300942 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300943 for (int col = 0; col < 4; ++col)
944 {
945 EXPECT_EQ(GLColor(expectedRedChannel[view][row][col], 0, 0, 255),
946 GetViewColor(col, row, view));
947 }
Martin Radev553590a2017-07-31 16:40:39 +0300948 }
949 }
950}
951
952// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
953// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +0300954TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +0300955{
956 if (!requestMultiviewExtension())
957 {
958 return;
959 }
960
Martin Radev3c25ad02017-08-22 17:36:53 +0300961 createFBO(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +0300962
963 // Create multiview program.
964 const std::string &vs =
965 "#version 300 es\n"
966 "#extension GL_OVR_multiview2 : require\n"
967 "layout(num_views = 2) in;\n"
968 "layout(location = 0) in vec2 vPosition;\n"
969 "layout(location = 1) in float offsetX;\n"
970 "void main()\n"
971 "{\n"
972 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
973 " p.x += offsetX;\n"
974 " gl_Position = p;\n"
975 "}\n";
976
977 const std::string &fs =
978 "#version 300 es\n"
979 "#extension GL_OVR_multiview2 : require\n"
980 "precision mediump float;\n"
981 "out vec4 col;\n"
982 "void main()\n"
983 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300984 " col = vec4(1,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300985 "}\n";
986
987 ANGLE_GL_PROGRAM(program, vs, fs);
988
989 const std::string &dummyVS =
990 "#version 300 es\n"
991 "layout(location = 0) in vec2 vPosition;\n"
992 "layout(location = 1) in float offsetX;\n"
993 "void main()\n"
994 "{\n"
995 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
996 "}\n";
997
998 const std::string &dummyFS =
999 "#version 300 es\n"
1000 "precision mediump float;\n"
1001 "out vec4 col;\n"
1002 "void main()\n"
1003 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001004 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001005 "}\n";
1006
1007 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
1008
1009 GLBuffer xOffsetVBO;
1010 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1011 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1012 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1013 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1014
1015 GLBuffer vertexVBO;
1016 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1017 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1018 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1019 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1020
1021 GLVertexArray vao[2];
1022 for (size_t i = 0u; i < 2u; ++i)
1023 {
1024 glBindVertexArray(vao[i]);
1025
1026 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1027 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1028 glEnableVertexAttribArray(0);
1029
1030 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1031 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1032 glEnableVertexAttribArray(1);
1033 }
1034 ASSERT_GL_NO_ERROR();
1035
1036 glViewport(0, 0, 1, 1);
1037 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001038 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001039 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001040
1041 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1042 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1043 // bits are cleared.
1044 glUseProgram(dummyProgram);
1045 glBindVertexArray(vao[0]);
1046 glVertexAttribDivisor(1, 0);
1047 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1048 glUseProgram(0);
1049 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1050 ASSERT_GL_NO_ERROR();
1051
1052 // Check that vertexAttribDivisor uses the number of views to update the divisor.
1053 glUseProgram(program);
1054 glVertexAttribDivisor(1, 1);
1055 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001056 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1057 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001058
1059 // Clear the buffers and propagate divisor to the driver.
1060 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1061 // dirty bits when useProgram is called.
1062 glUseProgram(dummyProgram);
1063 glVertexAttribDivisor(1, 1);
1064 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1065 glUseProgram(0);
1066 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1067 ASSERT_GL_NO_ERROR();
1068
1069 // Check that useProgram uses the number of views to update the divisor.
1070 glUseProgram(program);
1071 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001072 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1073 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001074
1075 // We go through similar steps as before.
1076 glUseProgram(dummyProgram);
1077 glVertexAttribDivisor(1, 1);
1078 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1079 glUseProgram(0);
1080 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1081 ASSERT_GL_NO_ERROR();
1082
1083 // Check that bindVertexArray uses the number of views to update the divisor.
1084 {
1085 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1086 // divisor for vao[1] only.
1087 glBindVertexArray(vao[1]);
1088 glUseProgram(program);
1089 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1090 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1091 glBindVertexArray(0);
1092 ASSERT_GL_NO_ERROR();
1093 }
1094 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1095 // adjusts the divisor.
1096 glBindVertexArray(vao[0]);
1097 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001098 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1099 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001100}
1101
Martin Radev0d671c92017-08-10 16:41:52 +03001102// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1103// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001104TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001105{
1106 if (!requestMultiviewExtension())
1107 {
1108 return;
1109 }
1110
1111 const std::string vsSource =
1112 "#version 300 es\n"
1113 "#extension GL_OVR_multiview : require\n"
1114 "layout(num_views = 2) in;\n"
1115 "in vec3 vPosition;\n"
1116 "void main()\n"
1117 "{\n"
1118 " gl_Position.x = 2.0;\n"
1119 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1120 "}\n";
1121
1122 const std::string fsSource =
1123 "#version 300 es\n"
1124 "#extension GL_OVR_multiview : require\n"
1125 "precision mediump float;\n"
1126 "out vec4 col;\n"
1127 "void main()\n"
1128 "{\n"
1129 " col = vec4(1,0,0,0);\n"
1130 "}\n";
1131 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1132 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001133 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001134
1135 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1136 ASSERT_GL_NO_ERROR();
1137 EXPECT_GL_FALSE(result);
1138}
1139
1140// Test that there are fragments passing the occlusion query if only view 0 can produce
1141// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001142TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001143{
1144 if (!requestMultiviewExtension())
1145 {
1146 return;
1147 }
1148
1149 const std::string vsSource =
1150 "#version 300 es\n"
1151 "#extension GL_OVR_multiview : require\n"
1152 "layout(num_views = 2) in;\n"
1153 "in vec3 vPosition;\n"
1154 "void main()\n"
1155 "{\n"
1156 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1157 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1158 "}\n";
1159
1160 const std::string fsSource =
1161 "#version 300 es\n"
1162 "#extension GL_OVR_multiview : require\n"
1163 "precision mediump float;\n"
1164 "out vec4 col;\n"
1165 "void main()\n"
1166 "{\n"
1167 " col = vec4(1,0,0,0);\n"
1168 "}\n";
1169 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1170 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001171 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001172
1173 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1174 ASSERT_GL_NO_ERROR();
1175 EXPECT_GL_TRUE(result);
1176}
1177
1178// Test that there are fragments passing the occlusion query if only view 1 can produce
1179// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001180TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001181{
1182 if (!requestMultiviewExtension())
1183 {
1184 return;
1185 }
1186
1187 const std::string vsSource =
1188 "#version 300 es\n"
1189 "#extension GL_OVR_multiview : require\n"
1190 "layout(num_views = 2) in;\n"
1191 "in vec3 vPosition;\n"
1192 "void main()\n"
1193 "{\n"
1194 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1195 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1196 "}\n";
1197
1198 const std::string fsSource =
1199 "#version 300 es\n"
1200 "#extension GL_OVR_multiview : require\n"
1201 "precision mediump float;\n"
1202 "out vec4 col;\n"
1203 "void main()\n"
1204 "{\n"
1205 " col = vec4(1,0,0,0);\n"
1206 "}\n";
1207 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1208 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001209 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001210
1211 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1212 ASSERT_GL_NO_ERROR();
1213 EXPECT_GL_TRUE(result);
1214}
1215
Martin Radev41ac68e2017-06-06 12:16:58 +03001216// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1217// compiles and links without an error.
1218TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1219{
1220 if (!requestMultiviewExtension())
1221 {
1222 return;
1223 }
1224
1225 const std::string vsSource =
1226 "#version 300 es\n"
1227 "#extension GL_OVR_multiview : require\n"
1228 "layout(num_views = 2) in;\n"
1229 "void main()\n"
1230 "{\n"
1231 "}\n";
1232
1233 const std::string fsSource =
1234 "#version 300 es\n"
1235 "#extension GL_OVR_multiview : require\n"
1236 "precision mediump float;\n"
1237 "void main()\n"
1238 "{\n"
1239 "}\n";
1240
1241 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1242 glUseProgram(program);
1243
1244 EXPECT_GL_NO_ERROR();
1245}
1246
1247// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1248// without an error.
1249TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1250{
1251 if (!requestMultiviewExtension())
1252 {
1253 return;
1254 }
1255
1256 const std::string vsSource =
1257 "#version 300 es\n"
1258 "#extension GL_OVR_multiview2 : require\n"
1259 "layout(num_views = 2) in;\n"
1260 "void main()\n"
1261 "{\n"
1262 " if (gl_ViewID_OVR == 0u) {\n"
1263 " gl_Position = vec4(1,0,0,1);\n"
1264 " } else {\n"
1265 " gl_Position = vec4(-1,0,0,1);\n"
1266 " }\n"
1267 "}\n";
1268
1269 const std::string fsSource =
1270 "#version 300 es\n"
1271 "#extension GL_OVR_multiview2 : require\n"
1272 "precision mediump float;\n"
1273 "void main()\n"
1274 "{\n"
1275 "}\n";
1276
1277 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1278 glUseProgram(program);
1279
1280 EXPECT_GL_NO_ERROR();
1281}
1282
1283// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1284// without an error.
1285TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1286{
1287 if (!requestMultiviewExtension())
1288 {
1289 return;
1290 }
1291
1292 const std::string vsSource =
1293 "#version 300 es\n"
1294 "#extension GL_OVR_multiview2 : require\n"
1295 "layout(num_views = 2) in;\n"
1296 "void main()\n"
1297 "{\n"
1298 "}\n";
1299
1300 const std::string fsSource =
1301 "#version 300 es\n"
1302 "#extension GL_OVR_multiview2 : require\n"
1303 "precision mediump float;\n"
1304 "out vec4 col;\n"
1305 "void main()\n"
1306 "{\n"
1307 " if (gl_ViewID_OVR == 0u) {\n"
1308 " col = vec4(1,0,0,1);\n"
1309 " } else {\n"
1310 " col = vec4(-1,0,0,1);\n"
1311 " }\n"
1312 "}\n";
1313
1314 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1315 glUseProgram(program);
1316
1317 EXPECT_GL_NO_ERROR();
1318}
1319
Martin Radev61bd9992017-08-11 13:10:55 +03001320// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001321TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001322{
1323 if (!requestMultiviewExtension())
1324 {
1325 return;
1326 }
1327
1328 const std::string vsSource =
1329 "#version 300 es\n"
1330 "#extension GL_OVR_multiview : require\n"
1331 "layout(num_views = 2) in;\n"
1332 "layout(location=0) in vec2 vPosition;\n"
1333 "void main()\n"
1334 "{\n"
1335 " gl_PointSize = 1.0;\n"
1336 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1337 "}\n";
1338
1339 const std::string fsSource =
1340 "#version 300 es\n"
1341 "#extension GL_OVR_multiview : require\n"
1342 "precision mediump float;\n"
1343 "out vec4 col;\n"
1344 "void main()\n"
1345 "{\n"
1346 " col = vec4(1,0,0,1);\n"
1347 "}\n";
1348 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1349 glUseProgram(program);
1350
Martin Radev3c25ad02017-08-22 17:36:53 +03001351 const int kViewWidth = 4;
1352 const int kViewHeight = 2;
1353 const int kNumViews = 2;
1354 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001355
1356 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1357 std::vector<Vector2> vertexDataInClipSpace =
1358 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1359 setupGeometry(vertexDataInClipSpace);
1360
1361 glDrawArrays(GL_POINTS, 0, 2);
1362
Martin Radev3c25ad02017-08-22 17:36:53 +03001363 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1364 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
1365 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001366}
1367
1368// The test checks that GL_LINES is correctly rendered.
1369// The behavior of this test is not guaranteed by the spec:
1370// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1371// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1372// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1373// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001374TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001375{
1376 if (!requestMultiviewExtension())
1377 {
1378 return;
1379 }
1380
1381 GLuint program = CreateSimplePassthroughProgram();
1382 ASSERT_NE(program, 0u);
1383 glUseProgram(program);
1384 ASSERT_GL_NO_ERROR();
1385
Martin Radev3c25ad02017-08-22 17:36:53 +03001386 const int kViewWidth = 4;
1387 const int kViewHeight = 2;
1388 const int kNumViews = 2;
1389 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001390
1391 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1392 std::vector<Vector2> vertexDataInClipSpace =
1393 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1394 setupGeometry(vertexDataInClipSpace);
1395
1396 glDrawArrays(GL_LINES, 0, 2);
1397
Martin Radev3c25ad02017-08-22 17:36:53 +03001398 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1399 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
1400 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001401
1402 glDeleteProgram(program);
1403}
1404
1405// The test checks that GL_LINE_STRIP is correctly rendered.
1406// The behavior of this test is not guaranteed by the spec:
1407// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1408// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1409// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1410// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001411TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001412{
1413 if (!requestMultiviewExtension())
1414 {
1415 return;
1416 }
1417
1418 GLuint program = CreateSimplePassthroughProgram();
1419 ASSERT_NE(program, 0u);
1420 glUseProgram(program);
1421 ASSERT_GL_NO_ERROR();
1422
Martin Radev3c25ad02017-08-22 17:36:53 +03001423 const int kViewWidth = 4;
1424 const int kViewHeight = 2;
1425 const int kNumViews = 2;
1426 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001427
1428 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1429 std::vector<Vector2> vertexDataInClipSpace =
1430 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1431 setupGeometry(vertexDataInClipSpace);
1432
1433 glDrawArrays(GL_LINE_STRIP, 0, 3);
1434
Martin Radev3c25ad02017-08-22 17:36:53 +03001435 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1436 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
1437 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001438
1439 glDeleteProgram(program);
1440}
1441
1442// The test checks that GL_LINE_LOOP is correctly rendered.
1443// The behavior of this test is not guaranteed by the spec:
1444// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1445// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1446// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1447// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001448TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001449{
1450 if (!requestMultiviewExtension())
1451 {
1452 return;
1453 }
1454
1455 GLuint program = CreateSimplePassthroughProgram();
1456 ASSERT_NE(program, 0u);
1457 glUseProgram(program);
1458 ASSERT_GL_NO_ERROR();
1459
Martin Radev3c25ad02017-08-22 17:36:53 +03001460 const int kViewWidth = 4;
1461 const int kViewHeight = 4;
1462 const int kNumViews = 2;
1463 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001464
1465 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1466 Vector2I(0, 3)};
1467 std::vector<Vector2> vertexDataInClipSpace =
1468 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1469 setupGeometry(vertexDataInClipSpace);
1470
1471 glDrawArrays(GL_LINE_LOOP, 0, 4);
1472
Martin Radev3c25ad02017-08-22 17:36:53 +03001473 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1474 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1475 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
1476 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001477
1478 glDeleteProgram(program);
1479}
1480
1481// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001482TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001483{
1484 if (!requestMultiviewExtension())
1485 {
1486 return;
1487 }
1488
1489 GLuint program = CreateSimplePassthroughProgram();
1490 ASSERT_NE(program, 0u);
1491 glUseProgram(program);
1492 ASSERT_GL_NO_ERROR();
1493
1494 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1495 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1496 setupGeometry(vertexDataInClipSpace);
1497
Martin Radev3c25ad02017-08-22 17:36:53 +03001498 const int kViewWidth = 2;
1499 const int kViewHeight = 2;
1500 const int kNumViews = 2;
1501 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001502
1503 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1504
Martin Radev3c25ad02017-08-22 17:36:53 +03001505 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {{{0, 0}, {0, 255}},
1506 {{0, 0}, {0, 255}}};
1507 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001508
1509 glDeleteProgram(program);
1510}
1511
1512// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001513TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001514{
1515 if (!requestMultiviewExtension())
1516 {
1517 return;
1518 }
1519
1520 GLuint program = CreateSimplePassthroughProgram();
1521 ASSERT_NE(program, 0u);
1522 glUseProgram(program);
1523 ASSERT_GL_NO_ERROR();
1524
1525 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1526 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1527 setupGeometry(vertexDataInClipSpace);
1528
Martin Radev3c25ad02017-08-22 17:36:53 +03001529 const int kViewWidth = 2;
1530 const int kViewHeight = 2;
1531 const int kNumViews = 2;
1532 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001533
1534 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1535
Martin Radev3c25ad02017-08-22 17:36:53 +03001536 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {{{0, 0}, {0, 255}},
1537 {{0, 0}, {0, 255}}};
1538 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001539
1540 glDeleteProgram(program);
1541}
1542
1543// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1544// bounds. The test does not rely on the actual line width being greater than 1.0.
Martin Radev3c25ad02017-08-22 17:36:53 +03001545TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
Martin Radev61bd9992017-08-11 13:10:55 +03001546{
1547 if (!requestMultiviewExtension())
1548 {
1549 return;
1550 }
1551
Martin Radev3c25ad02017-08-22 17:36:53 +03001552 createFBO(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +03001553
1554 GLint viewportOffsets[4] = {1, 0, 3, 0};
1555 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1556 mColorTexture, 0, 2, &viewportOffsets[0]);
1557 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
1558 mDepthTexture, 0, 2, &viewportOffsets[0]);
1559
1560 glViewport(0, 0, 1, 1);
1561 glScissor(0, 0, 1, 1);
1562 glEnable(GL_SCISSOR_TEST);
1563
1564 const std::string vsSource =
1565 "#version 300 es\n"
1566 "#extension GL_OVR_multiview2 : require\n"
1567 "layout(num_views = 2) in;\n"
1568 "layout(location=0) in vec2 vPosition;\n"
1569 "void main()\n"
1570 "{\n"
1571 " gl_PointSize = 10.0;\n"
1572 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1573 "}\n";
1574
1575 const std::string fsSource =
1576 "#version 300 es\n"
1577 "#extension GL_OVR_multiview2 : require\n"
1578 "precision mediump float;\n"
1579 "out vec4 col;\n"
1580 "void main()\n"
1581 "{\n"
1582 " if (gl_ViewID_OVR == 0u) {\n"
1583 " col = vec4(1,0,0,1);\n"
1584 " } else {\n"
1585 " col = vec4(0,1,0,1);\n"
1586 " }\n"
1587 "}\n";
1588 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1589 glUseProgram(program);
1590
1591 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1592 const std::vector<Vector2> &vertexDataInClipSpace =
1593 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001594
1595 GLBuffer vbo;
1596 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1597 glBufferData(GL_ARRAY_BUFFER, vertexDataInClipSpace.size() * sizeof(Vector2),
1598 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1599 glEnableVertexAttribArray(0);
1600 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
Martin Radev61bd9992017-08-11 13:10:55 +03001601
1602 // Test rendering points.
1603 {
1604 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1605 glDrawArrays(GL_POINTS, 0, 2);
1606 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1607 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1608 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1609 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1610 }
1611
1612 // Test rendering lines.
1613 {
1614 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1615 glLineWidth(10.f);
1616 glDrawArrays(GL_LINES, 0, 2);
1617 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1618 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1619 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1620 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1621 }
1622}
1623
Martin Radev3c25ad02017-08-22 17:36:53 +03001624MultiviewTestParams SideBySideOpenGL()
1625{
1626 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, egl_platform::OPENGL());
1627}
1628
1629MultiviewTestParams LayeredOpenGL()
1630{
1631 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, egl_platform::OPENGL());
1632}
1633
1634MultiviewTestParams SideBySideD3D11()
1635{
1636 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, egl_platform::D3D11());
1637}
1638
Martin Radev8f276e22017-05-30 12:05:52 +03001639ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest, ES31_OPENGL());
Martin Radev3c25ad02017-08-22 17:36:53 +03001640ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest, SideBySideOpenGL(), LayeredOpenGL());
1641ANGLE_INSTANTIATE_TEST(MultiviewRenderTest, SideBySideOpenGL(), LayeredOpenGL());
1642ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest, SideBySideOpenGL(), LayeredOpenGL());
1643ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest, SideBySideOpenGL(), SideBySideD3D11());
1644ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest, SideBySideOpenGL(), LayeredOpenGL());
Martin Radev0d671c92017-08-10 16:41:52 +03001645ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest, ES3_OPENGL());