blob: 7350c69e516b25b03d32c92abeb516bb6b8259e6 [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
Martin Radevc1d4e552017-08-21 12:01:10 +030010#include "platform/WorkaroundsD3D.h"
Olli Etuahof26b27e2018-08-17 11:01:19 +030011#include "test_utils/MultiviewTest.h"
Martin Radev14a26ae2017-07-24 15:56:29 +030012#include "test_utils/gl_raii.h"
13
14using namespace angle;
15
Martin Radev61bd9992017-08-11 13:10:55 +030016namespace
17{
Martin Radev61bd9992017-08-11 13:10:55 +030018
19std::vector<Vector2> ConvertPixelCoordinatesToClipSpace(const std::vector<Vector2I> &pixels,
20 int width,
21 int height)
22{
23 std::vector<Vector2> result(pixels.size());
24 for (size_t i = 0; i < pixels.size(); ++i)
25 {
26 const auto &pixel = pixels[i];
27 float pixelCenterRelativeX = (static_cast<float>(pixel.x()) + .5f) / width;
28 float pixelCenterRelativeY = (static_cast<float>(pixel.y()) + .5f) / height;
29 float xInClipSpace = 2.f * pixelCenterRelativeX - 1.f;
30 float yInClipSpace = 2.f * pixelCenterRelativeY - 1.f;
31 result[i] = Vector2(xInClipSpace, yInClipSpace);
32 }
33 return result;
34}
35} // namespace
36
Olli Etuahof26b27e2018-08-17 11:01:19 +030037struct MultiviewRenderTestParams final : public MultiviewImplementationParams
Martin Radev3c25ad02017-08-22 17:36:53 +030038{
Olli Etuahof26b27e2018-08-17 11:01:19 +030039 MultiviewRenderTestParams(GLenum multiviewLayout,
40 const MultiviewImplementationParams &implementationParams)
Martin Radevc1d4e552017-08-21 12:01:10 +030041 : MultiviewImplementationParams(implementationParams), mMultiviewLayout(multiviewLayout)
Martin Radev3c25ad02017-08-22 17:36:53 +030042 {
43 ASSERT(multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE ||
44 multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
45 }
46 GLenum mMultiviewLayout;
47};
48
Olli Etuahof26b27e2018-08-17 11:01:19 +030049std::ostream &operator<<(std::ostream &os, const MultiviewRenderTestParams &params)
Martin Radev3c25ad02017-08-22 17:36:53 +030050{
Martin Radevc1d4e552017-08-21 12:01:10 +030051 const MultiviewImplementationParams &base =
52 static_cast<const MultiviewImplementationParams &>(params);
Martin Radev3c25ad02017-08-22 17:36:53 +030053 os << base;
54 switch (params.mMultiviewLayout)
55 {
56 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
57 os << "_layered";
58 break;
59 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
60 os << "_side_by_side";
61 break;
62 default:
63 UNREACHABLE();
64 }
65 return os;
66}
67
Olli Etuaho4836acc2018-08-20 15:23:18 +030068class MultiviewFramebufferTestBase : public MultiviewTestBase
Martin Radev8f276e22017-05-30 12:05:52 +030069{
70 protected:
Olli Etuaho4836acc2018-08-20 15:23:18 +030071 MultiviewFramebufferTestBase(const PlatformParameters &params, GLenum multiviewLayout)
Olli Etuahof26b27e2018-08-17 11:01:19 +030072 : MultiviewTestBase(params),
Martin Radev3c25ad02017-08-22 17:36:53 +030073 mViewWidth(0),
74 mViewHeight(0),
Olli Etuaho4836acc2018-08-20 15:23:18 +030075 mNumViews(0),
Olli Etuaho44ae8992018-08-20 15:37:09 +030076 mColorTexture(0u),
77 mDepthTexture(0u),
78 mDrawFramebuffer(0u),
Olli Etuaho4836acc2018-08-20 15:23:18 +030079 mMultiviewLayout(multiviewLayout)
Martin Radev8f276e22017-05-30 12:05:52 +030080 {
Martin Radev3c25ad02017-08-22 17:36:53 +030081 }
Olli Etuaho44ae8992018-08-20 15:37:09 +030082
Olli Etuaho4836acc2018-08-20 15:23:18 +030083 void FramebufferTestSetUp() { MultiviewTestBase::MultiviewTestBaseSetUp(); }
Olli Etuaho44ae8992018-08-20 15:37:09 +030084
85 void FramebufferTestTearDown()
86 {
87 freeFBOs();
88 MultiviewTestBase::MultiviewTestBaseTearDown();
89 }
90
Olli Etuaho4836acc2018-08-20 15:23:18 +030091 void updateFBOs(int viewWidth, int height, int numViews, int numLayers, int baseViewIndex)
Martin Radev3c25ad02017-08-22 17:36:53 +030092 {
Martin Radev72b4e1e2017-08-31 15:42:56 +030093 ASSERT(numViews + baseViewIndex <= numLayers);
94
Olli Etuaho44ae8992018-08-20 15:37:09 +030095 freeFBOs();
96
Martin Radev3c25ad02017-08-22 17:36:53 +030097 mViewWidth = viewWidth;
98 mViewHeight = height;
99 mNumViews = numViews;
Martin Radev8f276e22017-05-30 12:05:52 +0300100
Olli Etuaho44ae8992018-08-20 15:37:09 +0300101 glGenTextures(1, &mColorTexture);
102 glGenTextures(1, &mDepthTexture);
Martin Radev0abb7a22017-08-28 15:34:45 +0300103
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300104 CreateMultiviewBackingTextures(mMultiviewLayout, viewWidth, height, numLayers,
105 mColorTexture, mDepthTexture, 0u);
Martin Radev3c25ad02017-08-22 17:36:53 +0300106
Olli Etuaho44ae8992018-08-20 15:37:09 +0300107 glGenFramebuffers(1, &mDrawFramebuffer);
108
Martin Radev3c25ad02017-08-22 17:36:53 +0300109 // Create draw framebuffer to be used for multiview rendering.
110 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300111 AttachMultiviewTextures(GL_DRAW_FRAMEBUFFER, mMultiviewLayout, viewWidth, numViews,
112 baseViewIndex, mColorTexture, mDepthTexture, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300113
Martin Radev8f276e22017-05-30 12:05:52 +0300114 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
115
116 // Create read framebuffer to be used to retrieve the pixel information for testing
117 // purposes.
Martin Radev3c25ad02017-08-22 17:36:53 +0300118 switch (mMultiviewLayout)
119 {
120 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
121 mReadFramebuffer.resize(1);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300122 glGenFramebuffers(1, mReadFramebuffer.data());
Martin Radev3c25ad02017-08-22 17:36:53 +0300123 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
124 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
125 mColorTexture, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300126 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
127 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300128 break;
129 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
Martin Radev72b4e1e2017-08-31 15:42:56 +0300130 mReadFramebuffer.resize(numLayers);
Shahbaz Youssefic4097442018-08-22 12:14:52 -0400131 glGenFramebuffers(static_cast<GLsizei>(mReadFramebuffer.size()),
132 mReadFramebuffer.data());
Martin Radev72b4e1e2017-08-31 15:42:56 +0300133 for (int i = 0; i < numLayers; ++i)
Martin Radev3c25ad02017-08-22 17:36:53 +0300134 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300135 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
136 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
137 mColorTexture, 0, i);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300138 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
139 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300140 }
141 break;
142 default:
143 UNREACHABLE();
144 }
Martin Radev8f276e22017-05-30 12:05:52 +0300145
146 // Clear the buffers.
Martin Radev3c25ad02017-08-22 17:36:53 +0300147 glViewport(0, 0, viewWidth, height);
148 if (mMultiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
149 {
150 // Enable the scissor test only for side-by-side framebuffers.
151 glEnable(GL_SCISSOR_TEST);
152 glScissor(0, 0, viewWidth, height);
153 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300154 }
Martin Radev8f276e22017-05-30 12:05:52 +0300155
Olli Etuaho4836acc2018-08-20 15:23:18 +0300156 void updateFBOs(int viewWidth, int height, int numViews)
Martin Radev72b4e1e2017-08-31 15:42:56 +0300157 {
Olli Etuaho4836acc2018-08-20 15:23:18 +0300158 updateFBOs(viewWidth, height, numViews, numViews, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300159 }
160
Olli Etuaho4836acc2018-08-20 15:23:18 +0300161 void bindMemberDrawFramebuffer() { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer); }
162
Martin Radev3c25ad02017-08-22 17:36:53 +0300163 GLColor GetViewColor(int x, int y, int view)
164 {
165 switch (mMultiviewLayout)
166 {
167 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300168 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
Martin Radev3c25ad02017-08-22 17:36:53 +0300169 return ReadColor(view * mViewWidth + x, y);
170 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
171 ASSERT(static_cast<size_t>(view) < mReadFramebuffer.size());
172 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
173 return ReadColor(x, y);
174 default:
175 UNREACHABLE();
176 }
177 return GLColor(0, 0, 0, 0);
Martin Radev8f276e22017-05-30 12:05:52 +0300178 }
179
Martin Radev3c25ad02017-08-22 17:36:53 +0300180 int mViewWidth;
181 int mViewHeight;
182 int mNumViews;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300183
Olli Etuaho44ae8992018-08-20 15:37:09 +0300184 GLuint mColorTexture;
185 GLuint mDepthTexture;
186
Olli Etuaho4836acc2018-08-20 15:23:18 +0300187 private:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300188 GLuint mDrawFramebuffer;
189 std::vector<GLuint> mReadFramebuffer;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300190 GLenum mMultiviewLayout;
Olli Etuaho44ae8992018-08-20 15:37:09 +0300191
192 void freeFBOs()
193 {
194 if (mDrawFramebuffer)
195 {
196 glDeleteFramebuffers(1, &mDrawFramebuffer);
197 mDrawFramebuffer = 0;
198 }
199 if (!mReadFramebuffer.empty())
200 {
Shahbaz Youssefic4097442018-08-22 12:14:52 -0400201 GLsizei framebufferCount = static_cast<GLsizei>(mReadFramebuffer.size());
202 glDeleteFramebuffers(framebufferCount, mReadFramebuffer.data());
Olli Etuaho44ae8992018-08-20 15:37:09 +0300203 mReadFramebuffer.clear();
204 }
205 if (mDepthTexture)
206 {
207 glDeleteTextures(1, &mDepthTexture);
208 mDepthTexture = 0;
209 }
210 if (mColorTexture)
211 {
212 glDeleteTextures(1, &mColorTexture);
213 mColorTexture = 0;
214 }
215 }
Martin Radev8f276e22017-05-30 12:05:52 +0300216};
217
Olli Etuaho4836acc2018-08-20 15:23:18 +0300218class MultiviewRenderTest : public MultiviewFramebufferTestBase,
Olli Etuahof26b27e2018-08-17 11:01:19 +0300219 public ::testing::TestWithParam<MultiviewRenderTestParams>
Martin Radev8f276e22017-05-30 12:05:52 +0300220{
221 protected:
Olli Etuaho4836acc2018-08-20 15:23:18 +0300222 MultiviewRenderTest() : MultiviewFramebufferTestBase(GetParam(), GetParam().mMultiviewLayout) {}
223 void SetUp() override { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300224 void TearDown() override { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
Martin Radevc1d4e552017-08-21 12:01:10 +0300225
226 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
227 {
228 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
229 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300230};
231
Jamie Madill04c084d2018-08-08 15:49:28 -0400232constexpr char kDualViewVSSource[] = R"(#version 300 es
233#extension GL_OVR_multiview : require
234layout(num_views = 2) in;
235in vec4 vPosition;
236void main()
237{
238 gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x*0.5 + 0.5 : vPosition.x*0.5);
239 gl_Position.yzw = vPosition.yzw;
240})";
241
242constexpr char kDualViewFSSource[] = R"(#version 300 es
243#extension GL_OVR_multiview : require
244precision mediump float;
245out vec4 col;
246void main()
247{
248 col = vec4(0,1,0,1);
249})";
250
Martin Radev3c25ad02017-08-22 17:36:53 +0300251class MultiviewRenderDualViewTest : public MultiviewRenderTest
252{
253 protected:
254 MultiviewRenderDualViewTest() : mProgram(0u) {}
Martin Radev8f276e22017-05-30 12:05:52 +0300255
256 void SetUp() override
257 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300258 MultiviewRenderTest::SetUp();
Martin Radev8f276e22017-05-30 12:05:52 +0300259
260 if (!requestMultiviewExtension())
261 {
262 return;
263 }
264
Olli Etuaho4836acc2018-08-20 15:23:18 +0300265 updateFBOs(2, 1, 2);
Jamie Madill04c084d2018-08-08 15:49:28 -0400266 mProgram = CompileProgram(kDualViewVSSource, kDualViewFSSource);
Martin Radev61bd9992017-08-11 13:10:55 +0300267 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300268 glUseProgram(mProgram);
269 ASSERT_GL_NO_ERROR();
270 }
271
Olli Etuaho44ae8992018-08-20 15:37:09 +0300272 void TearDown() override
273 {
274 if (mProgram != 0u)
275 {
276 glDeleteProgram(mProgram);
277 mProgram = 0u;
278 }
279
280 MultiviewRenderTest::TearDown();
281 }
282
Martin Radev8f276e22017-05-30 12:05:52 +0300283 void checkOutput()
284 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300285 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +0300286 EXPECT_EQ(GLColor::green, GetViewColor(1, 0, 0));
287 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300288 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(1, 0, 1));
Martin Radev8f276e22017-05-30 12:05:52 +0300289 }
290
291 GLuint mProgram;
292};
293
Olli Etuaho44ae8992018-08-20 15:37:09 +0300294// Base class for tests that care mostly about draw call validity and not rendering results.
295class MultiviewDrawValidationTest : public MultiviewTest
Jamie Madill04c084d2018-08-08 15:49:28 -0400296{
297 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300298 MultiviewDrawValidationTest() : MultiviewTest() {}
Jamie Madill04c084d2018-08-08 15:49:28 -0400299
Olli Etuaho44ae8992018-08-20 15:37:09 +0300300 void initOnePixelColorTexture2D(GLuint texId)
Jamie Madill04c084d2018-08-08 15:49:28 -0400301 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300302 glBindTexture(GL_TEXTURE_2D, texId);
Jamie Madill04c084d2018-08-08 15:49:28 -0400303 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300304 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400305
Olli Etuaho44ae8992018-08-20 15:37:09 +0300306 // This initializes a simple VAO with a valid vertex buffer and index buffer with three
307 // vertices.
308 void initVAO(GLuint vao, GLuint vertexBuffer, GLuint indexBuffer)
309 {
310 glBindVertexArray(vao);
Jamie Madill04c084d2018-08-08 15:49:28 -0400311
312 const float kVertexData[3] = {0.0f};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300313 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400314 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
315
316 const unsigned int kIndices[3] = {0u, 1u, 2u};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300317 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400318 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
319 GL_STATIC_DRAW);
320 ASSERT_GL_NO_ERROR();
321 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400322};
323
Martin Radev3c25ad02017-08-22 17:36:53 +0300324class MultiviewOcclusionQueryTest : public MultiviewRenderTest
Martin Radev0d671c92017-08-10 16:41:52 +0300325{
326 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300327 MultiviewOcclusionQueryTest() {}
Martin Radev0d671c92017-08-10 16:41:52 +0300328
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400329 bool requestOcclusionQueryExtension()
330 {
331 if (extensionRequestable("GL_EXT_occlusion_query_boolean"))
332 {
333 glRequestExtensionANGLE("GL_EXT_occlusion_query_boolean");
334 }
335
336 if (!extensionEnabled("GL_EXT_occlusion_query_boolean"))
337 {
338 std::cout << "Test skipped due to missing GL_EXT_occlusion_query_boolean." << std::endl;
339 return false;
340 }
341 return true;
342 }
343
Martin Radev0d671c92017-08-10 16:41:52 +0300344 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
345 {
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400346 GLQueryEXT query;
347 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED, query);
Martin Radev0d671c92017-08-10 16:41:52 +0300348 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
349 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
350
351 GLuint result = GL_TRUE;
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400352 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT, &result);
Martin Radev0d671c92017-08-10 16:41:52 +0300353 return result;
354 }
355};
356
Olli Etuaho4bcaf992018-08-17 17:18:28 +0300357class MultiviewProgramGenerationTest : public MultiviewTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300358{
359 protected:
360 MultiviewProgramGenerationTest() {}
361};
362
Martin Radev3c25ad02017-08-22 17:36:53 +0300363class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300364{
365 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300366 MultiviewRenderPrimitiveTest() : mVBO(0u) {}
367
368 void SetUp() override
369 {
370 MultiviewRenderTest::SetUp();
371 glGenBuffers(1, &mVBO);
372 }
373
374 void TearDown() override
375 {
376 if (mVBO)
377 {
378 glDeleteBuffers(1, &mVBO);
379 mVBO = 0u;
380 }
381 MultiviewRenderTest::TearDown();
382 }
Martin Radev61bd9992017-08-11 13:10:55 +0300383
384 void setupGeometry(const std::vector<Vector2> &vertexData)
385 {
Martin Radev61bd9992017-08-11 13:10:55 +0300386 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
387 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
388 GL_STATIC_DRAW);
389 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500390 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +0300391 }
392
Martin Radev67a8a012017-09-08 13:03:52 +0300393 void checkGreenChannel(const GLubyte expectedGreenChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300394 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300395 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300396 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300397 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300398 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300399 for (int h = 0; h < mViewHeight; ++h)
400 {
401 size_t flatIndex =
402 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300403 EXPECT_EQ(GLColor(0, expectedGreenChannelData[flatIndex], 0,
404 expectedGreenChannelData[flatIndex]),
Martin Radev3c25ad02017-08-22 17:36:53 +0300405 GetViewColor(w, h, view));
406 }
Martin Radev61bd9992017-08-11 13:10:55 +0300407 }
408 }
409 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300410 GLuint mVBO;
Martin Radev61bd9992017-08-11 13:10:55 +0300411};
412
Olli Etuaho4836acc2018-08-20 15:23:18 +0300413class MultiviewSideBySideRenderTest : public MultiviewFramebufferTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300414 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev3c25ad02017-08-22 17:36:53 +0300415{
416 protected:
417 MultiviewSideBySideRenderTest()
Olli Etuaho4836acc2018-08-20 15:23:18 +0300418 : MultiviewFramebufferTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
Martin Radev3c25ad02017-08-22 17:36:53 +0300419 {
420 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300421
422 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
423 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
424 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
Martin Radevc1d4e552017-08-21 12:01:10 +0300425 {
426 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
427 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300428};
429
Olli Etuaho4836acc2018-08-20 15:23:18 +0300430class MultiviewLayeredRenderTest : public MultiviewFramebufferTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300431 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev72b4e1e2017-08-31 15:42:56 +0300432{
433 protected:
434 MultiviewLayeredRenderTest()
Olli Etuaho4836acc2018-08-20 15:23:18 +0300435 : MultiviewFramebufferTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE)
Martin Radev72b4e1e2017-08-31 15:42:56 +0300436 {
437 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300438 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
439 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
440 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
Martin Radevc1d4e552017-08-21 12:01:10 +0300441 {
442 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
443 }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300444};
445
Martin Radev14a26ae2017-07-24 15:56:29 +0300446// The test verifies that glDraw*Indirect:
447// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
448// than 1.
449// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +0300450TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300451{
452 if (!requestMultiviewExtension())
453 {
454 return;
455 }
456
Martin Radev14a26ae2017-07-24 15:56:29 +0300457 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +0300458
459 const std::string fsSource =
460 "#version 300 es\n"
461 "#extension GL_OVR_multiview : require\n"
462 "precision mediump float;\n"
463 "void main()\n"
464 "{}\n";
465
Olli Etuaho44ae8992018-08-20 15:37:09 +0300466 GLVertexArray vao;
467 GLBuffer vertexBuffer;
468 GLBuffer indexBuffer;
469 initVAO(vao, vertexBuffer, indexBuffer);
470
471 GLFramebuffer fbo;
472 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
473
Martin Radev14a26ae2017-07-24 15:56:29 +0300474 GLBuffer commandBuffer;
475 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
476 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
477 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
478 ASSERT_GL_NO_ERROR();
479
Olli Etuaho44ae8992018-08-20 15:37:09 +0300480 GLTexture tex2D;
481 initOnePixelColorTexture2D(tex2D);
482
Martin Radev14a26ae2017-07-24 15:56:29 +0300483 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
484 {
485 const std::string &vsSource =
486 "#version 300 es\n"
487 "#extension GL_OVR_multiview : require\n"
488 "layout(num_views = 2) in;\n"
489 "void main()\n"
490 "{}\n";
491 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
492 glUseProgram(program);
493
Olli Etuaho44ae8992018-08-20 15:37:09 +0300494 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
495 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300496
497 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
498 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
499
500 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
501 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
502 }
503
504 // Check that no errors are generated if the number of views is 1.
505 {
506 const std::string &vsSource =
507 "#version 300 es\n"
508 "#extension GL_OVR_multiview : require\n"
509 "layout(num_views = 1) in;\n"
510 "void main()\n"
511 "{}\n";
512 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
513 glUseProgram(program);
514
Olli Etuaho44ae8992018-08-20 15:37:09 +0300515 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
516 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300517
518 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
519 EXPECT_GL_NO_ERROR();
520
521 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
522 EXPECT_GL_NO_ERROR();
523 }
524}
525
Martin Radev7cf61662017-07-26 17:10:53 +0300526// The test verifies that glDraw*:
527// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
528// program differs.
529// 2) does not generate any error if the number of views is the same.
Martin Radev7cf61662017-07-26 17:10:53 +0300530TEST_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
Olli Etuaho44ae8992018-08-20 15:37:09 +0300554 GLVertexArray vao;
555 GLBuffer vertexBuffer;
556 GLBuffer indexBuffer;
557 initVAO(vao, vertexBuffer, indexBuffer);
558
559 GLFramebuffer fbo;
560 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
561
562 GLTexture tex2D;
563 initOnePixelColorTexture2D(tex2D);
564
Martin Radev7cf61662017-07-26 17:10:53 +0300565 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
566 // number of views.
567 {
568 // The framebuffer has only 1 view.
Olli Etuaho44ae8992018-08-20 15:37:09 +0300569 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
570 1, &viewportOffsets[0]);
Martin Radev7cf61662017-07-26 17:10:53 +0300571
572 glDrawArrays(GL_TRIANGLES, 0, 3);
573 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
574
575 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
576 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
577 }
578
579 // Check that no errors are generated if the number of views in both program and draw
580 // framebuffer matches.
581 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300582 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
583 2, &viewportOffsets[0]);
Martin Radev7cf61662017-07-26 17:10:53 +0300584
585 glDrawArrays(GL_TRIANGLES, 0, 3);
586 EXPECT_GL_NO_ERROR();
587
588 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
589 EXPECT_GL_NO_ERROR();
590 }
Martin Radevda8e2572017-09-12 17:21:16 +0300591}
Martin Radev7cf61662017-07-26 17:10:53 +0300592
Martin Radevda8e2572017-09-12 17:21:16 +0300593// The test verifies that glDraw* generates an INVALID_OPERATION error if the program does not use
594// the multiview extension, but the active draw framebuffer has more than one view.
595TEST_P(MultiviewDrawValidationTest, NumViewsMismatchForNonMultiviewProgram)
596{
597 if (!requestMultiviewExtension())
Martin Radev7cf61662017-07-26 17:10:53 +0300598 {
Martin Radevda8e2572017-09-12 17:21:16 +0300599 return;
Martin Radev7cf61662017-07-26 17:10:53 +0300600 }
Martin Radevda8e2572017-09-12 17:21:16 +0300601
602 const std::string &vsSourceNoMultiview =
603 "#version 300 es\n"
604 "void main()\n"
605 "{}\n";
606 const std::string &fsSourceNoMultiview =
607 "#version 300 es\n"
608 "precision mediump float;\n"
609 "void main()\n"
610 "{}\n";
611 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
612 glUseProgram(programNoMultiview);
613
Olli Etuaho44ae8992018-08-20 15:37:09 +0300614 GLVertexArray vao;
615 GLBuffer vertexBuffer;
616 GLBuffer indexBuffer;
617 initVAO(vao, vertexBuffer, indexBuffer);
618
619 GLFramebuffer fbo;
620 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
621
622 GLTexture tex2D;
623 initOnePixelColorTexture2D(tex2D);
624
Martin Radevda8e2572017-09-12 17:21:16 +0300625 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300626 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 2,
Martin Radevda8e2572017-09-12 17:21:16 +0300627 &viewportOffsets[0]);
628
629 glDrawArrays(GL_TRIANGLES, 0, 3);
630 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
631
632 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
633 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radev7cf61662017-07-26 17:10:53 +0300634}
635
Martin Radev7e69f762017-07-27 14:54:13 +0300636// The test verifies that glDraw*:
637// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
638// greater than 1 and there is an active transform feedback object.
639// 2) does not generate any error if the number of views in the draw framebuffer is 1.
640TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
641{
642 if (!requestMultiviewExtension())
643 {
644 return;
645 }
646
647 const GLint viewportOffsets[4] = {0, 0, 2, 0};
648
649 const std::string &vsSource =
Olli Etuaho3755c482017-10-13 15:40:26 +0300650 R"(#version 300 es
651 out float tfVarying;
652 void main()
653 {
654 tfVarying = 1.0;
655 })";
Martin Radev7e69f762017-07-27 14:54:13 +0300656 const std::string &fsSource =
Olli Etuaho3755c482017-10-13 15:40:26 +0300657 R"(#version 300 es
658 precision mediump float;
659 void main()
660 {})";
Jamie Madill04c084d2018-08-08 15:49:28 -0400661
Olli Etuaho3755c482017-10-13 15:40:26 +0300662 std::vector<std::string> tfVaryings;
Jamie Madill04c084d2018-08-08 15:49:28 -0400663 tfVaryings.emplace_back("tfVarying");
664 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(singleViewProgram, vsSource, fsSource, tfVaryings,
Olli Etuaho3755c482017-10-13 15:40:26 +0300665 GL_SEPARATE_ATTRIBS);
Jamie Madill04c084d2018-08-08 15:49:28 -0400666
667 std::vector<std::string> dualViewTFVaryings;
668 dualViewTFVaryings.emplace_back("gl_Position");
669 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(dualViewProgram, kDualViewVSSource, kDualViewFSSource,
670 dualViewTFVaryings, GL_SEPARATE_ATTRIBS);
Martin Radev7e69f762017-07-27 14:54:13 +0300671
Olli Etuaho44ae8992018-08-20 15:37:09 +0300672 GLVertexArray vao;
673 GLBuffer vertexBuffer;
674 GLBuffer indexBuffer;
675 initVAO(vao, vertexBuffer, indexBuffer);
676
Martin Radev7e69f762017-07-27 14:54:13 +0300677 GLBuffer tbo;
678 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
Jamie Madill04c084d2018-08-08 15:49:28 -0400679 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 16u, nullptr, GL_STATIC_DRAW);
Martin Radev7e69f762017-07-27 14:54:13 +0300680
681 GLTransformFeedback transformFeedback;
682 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
Olli Etuaho3755c482017-10-13 15:40:26 +0300683
684 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
685
Jamie Madill04c084d2018-08-08 15:49:28 -0400686 glUseProgram(dualViewProgram);
Martin Radev7e69f762017-07-27 14:54:13 +0300687 glBeginTransformFeedback(GL_TRIANGLES);
688 ASSERT_GL_NO_ERROR();
689
Olli Etuaho44ae8992018-08-20 15:37:09 +0300690 GLFramebuffer fbo;
691 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
692
693 GLTexture tex2D;
694 initOnePixelColorTexture2D(tex2D);
695
Martin Radev7e69f762017-07-27 14:54:13 +0300696 // Check that drawArrays generates an error when there is an active transform feedback object
697 // and the number of views in the draw framebuffer is greater than 1.
698 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300699 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
700 2, &viewportOffsets[0]);
Martin Radev7e69f762017-07-27 14:54:13 +0300701 glDrawArrays(GL_TRIANGLES, 0, 3);
702 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
703 }
704
Jamie Madill04c084d2018-08-08 15:49:28 -0400705 glEndTransformFeedback();
706
707 // Ending transform feedback should allow the draw to succeed.
708 {
709 glDrawArrays(GL_TRIANGLES, 0, 3);
710 EXPECT_GL_NO_ERROR();
711 }
712
713 // A paused transform feedback should still trigger an error.
714 glBeginTransformFeedback(GL_TRIANGLES);
715 glPauseTransformFeedback();
716 ASSERT_GL_NO_ERROR();
717
718 glDrawArrays(GL_TRIANGLES, 0, 3);
719 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
720
721 // Unbind transform feedback - should succeed.
722 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
723 glDrawArrays(GL_TRIANGLES, 0, 3);
724 ASSERT_GL_NO_ERROR();
725
726 // Rebind paused transform feedback - should fail.
727 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
728 glDrawArrays(GL_TRIANGLES, 0, 3);
729 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
730
731 glResumeTransformFeedback();
732 glEndTransformFeedback();
733
734 glUseProgram(singleViewProgram);
735 glBeginTransformFeedback(GL_TRIANGLES);
736 ASSERT_GL_NO_ERROR();
737
Martin Radev7e69f762017-07-27 14:54:13 +0300738 // Check that drawArrays does not generate an error when the number of views in the draw
739 // framebuffer is 1.
740 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300741 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
742 1, &viewportOffsets[0]);
Martin Radev7e69f762017-07-27 14:54:13 +0300743 glDrawArrays(GL_TRIANGLES, 0, 3);
744 EXPECT_GL_NO_ERROR();
745 }
746
747 glEndTransformFeedback();
748}
749
Martin Radevffe754b2017-07-31 10:38:07 +0300750// The test verifies that glDraw*:
751// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
752// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
753// 2) does not generate any error if the number of views in the draw framebuffer is 1.
754TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
755{
Yunchao He9550c602018-02-13 14:47:05 +0800756 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radevffe754b2017-07-31 10:38:07 +0300757
Olli Etuaho94c91a92018-07-19 15:10:24 +0300758 if (extensionRequestable("GL_EXT_disjoint_timer_query"))
759 {
760 glRequestExtensionANGLE("GL_EXT_disjoint_timer_query");
761 }
762
Yunchao He9550c602018-02-13 14:47:05 +0800763 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_disjoint_timer_query"));
Martin Radevffe754b2017-07-31 10:38:07 +0300764
Olli Etuaho44ae8992018-08-20 15:37:09 +0300765 ANGLE_GL_PROGRAM(dualViewProgram, kDualViewVSSource, kDualViewFSSource);
766
Martin Radevffe754b2017-07-31 10:38:07 +0300767 const GLint viewportOffsets[4] = {0, 0, 2, 0};
768 const std::string &vsSource =
769 "#version 300 es\n"
770 "void main()\n"
771 "{}\n";
772 const std::string &fsSource =
773 "#version 300 es\n"
774 "precision mediump float;\n"
775 "void main()\n"
776 "{}\n";
Jamie Madill04c084d2018-08-08 15:49:28 -0400777 ANGLE_GL_PROGRAM(singleViewProgram, vsSource, fsSource);
778 glUseProgram(singleViewProgram);
Martin Radevffe754b2017-07-31 10:38:07 +0300779
Olli Etuaho44ae8992018-08-20 15:37:09 +0300780 GLVertexArray vao;
781 GLBuffer vertexBuffer;
782 GLBuffer indexBuffer;
783 initVAO(vao, vertexBuffer, indexBuffer);
784
Martin Radevffe754b2017-07-31 10:38:07 +0300785 GLuint query = 0u;
786 glGenQueriesEXT(1, &query);
787 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
788
Olli Etuaho44ae8992018-08-20 15:37:09 +0300789 GLFramebuffer fbo;
790 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
791
792 GLTexture tex2D;
793 initOnePixelColorTexture2D(tex2D);
794
Martin Radevffe754b2017-07-31 10:38:07 +0300795 // Check first case.
796 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300797 glUseProgram(dualViewProgram);
798 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
799 2, &viewportOffsets[0]);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300800 glClear(GL_COLOR_BUFFER_BIT);
801 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radevffe754b2017-07-31 10:38:07 +0300802 glDrawArrays(GL_TRIANGLES, 0, 3);
803 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
804 }
805
806 // Check second case.
807 {
Jamie Madill04c084d2018-08-08 15:49:28 -0400808 glUseProgram(singleViewProgram);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300809 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
810 1, &viewportOffsets[0]);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300811 glClear(GL_COLOR_BUFFER_BIT);
812 EXPECT_GL_NO_ERROR();
Martin Radevffe754b2017-07-31 10:38:07 +0300813 glDrawArrays(GL_TRIANGLES, 0, 3);
814 EXPECT_GL_NO_ERROR();
815 }
816
817 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
818 glDeleteQueries(1, &query);
Jamie Madill04c084d2018-08-08 15:49:28 -0400819
820 // Check starting a query after a successful draw.
821 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300822 glUseProgram(dualViewProgram);
823 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
824 2, &viewportOffsets[0]);
Jamie Madill04c084d2018-08-08 15:49:28 -0400825 glClear(GL_COLOR_BUFFER_BIT);
826 EXPECT_GL_NO_ERROR();
827 glDrawArrays(GL_TRIANGLES, 0, 3);
828 EXPECT_GL_NO_ERROR();
829
830 glGenQueriesEXT(1, &query);
831 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
832
833 glDrawArrays(GL_TRIANGLES, 0, 3);
834 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
835
836 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
837 glDrawArrays(GL_TRIANGLES, 0, 3);
838 EXPECT_GL_NO_ERROR();
839
840 glDeleteQueries(1, &query);
841 }
Martin Radevffe754b2017-07-31 10:38:07 +0300842}
843
Martin Radev8f276e22017-05-30 12:05:52 +0300844// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300845TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300846{
847 if (!requestMultiviewExtension())
848 {
849 return;
850 }
851 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
852 ASSERT_GL_NO_ERROR();
853
854 checkOutput();
855}
856
857// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300858TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300859{
860 if (!requestMultiviewExtension())
861 {
862 return;
863 }
864 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
865 ASSERT_GL_NO_ERROR();
866
867 checkOutput();
868}
869
870// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300871TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300872{
873 if (!requestMultiviewExtension())
874 {
875 return;
876 }
877 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
878 ASSERT_GL_NO_ERROR();
879
880 checkOutput();
881}
882
883// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300884TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300885{
886 if (!requestMultiviewExtension())
887 {
888 return;
889 }
890
891 const std::string vsSource =
892 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300893 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300894 "layout(num_views = 4) in;\n"
895 "in vec4 vPosition;\n"
896 "void main()\n"
897 "{\n"
898 " if (gl_ViewID_OVR == 0u) {\n"
899 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
900 " } else if (gl_ViewID_OVR == 1u) {\n"
901 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
902 " } else if (gl_ViewID_OVR == 2u) {\n"
903 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
904 " } else {\n"
905 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
906 " }"
907 " gl_Position.yzw = vPosition.yzw;\n"
908 "}\n";
909
910 const std::string fsSource =
911 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300912 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300913 "precision mediump float;\n"
914 "out vec4 col;\n"
915 "void main()\n"
916 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300917 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300918 "}\n";
919
Olli Etuaho4836acc2018-08-20 15:23:18 +0300920 updateFBOs(4, 1, 4);
Martin Radev8f276e22017-05-30 12:05:52 +0300921 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +0300922
923 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
924 ASSERT_GL_NO_ERROR();
925
926 for (int i = 0; i < 4; ++i)
927 {
928 for (int j = 0; j < 4; ++j)
929 {
Martin Radev8f276e22017-05-30 12:05:52 +0300930 if (i == j)
931 {
Martin Radev67a8a012017-09-08 13:03:52 +0300932 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300933 }
934 else
935 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300936 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300937 }
938 }
939 }
940 EXPECT_GL_NO_ERROR();
941}
942
943// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300944TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +0300945{
946 if (!requestMultiviewExtension())
947 {
948 return;
949 }
950
951 const std::string vsSource =
952 "#version 300 es\n"
953 "#extension GL_OVR_multiview : require\n"
954 "layout(num_views = 2) in;\n"
955 "in vec4 vPosition;\n"
956 "void main()\n"
957 "{\n"
958 " vec4 p = vPosition;\n"
959 " if (gl_InstanceID == 1){\n"
960 " p.y = .5*p.y + .5;\n"
961 " } else {\n"
962 " p.y = p.y*.5;\n"
963 " }\n"
964 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x*0.5 + 0.5 : p.x*0.5);\n"
965 " gl_Position.yzw = p.yzw;\n"
966 "}\n";
967
968 const std::string fsSource =
969 "#version 300 es\n"
970 "#extension GL_OVR_multiview : require\n"
971 "precision mediump float;\n"
972 "out vec4 col;\n"
973 "void main()\n"
974 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300975 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300976 "}\n";
977
Martin Radev3c25ad02017-08-22 17:36:53 +0300978 const int kViewWidth = 2;
979 const int kViewHeight = 2;
980 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300981 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev8f276e22017-05-30 12:05:52 +0300982 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +0300983
Martin Radev67a8a012017-09-08 13:03:52 +0300984 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 2u);
Martin Radev8f276e22017-05-30 12:05:52 +0300985 ASSERT_GL_NO_ERROR();
986
Martin Radev67a8a012017-09-08 13:03:52 +0300987 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
988 {{255, 0}, {255, 0}}};
Martin Radev3c25ad02017-08-22 17:36:53 +0300989
990 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +0300991 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300992 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +0300993 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300994 for (int x = 0; x < 2; ++x)
995 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300996 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][y][x], 0,
997 expectedGreenChannel[view][y][x]),
Martin Radev3c25ad02017-08-22 17:36:53 +0300998 GetViewColor(x, y, view));
999 }
Martin Radev8f276e22017-05-30 12:05:52 +03001000 }
1001 }
1002}
1003
Martin Radev553590a2017-07-31 16:40:39 +03001004// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
1005// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
1006// offset of each quad are passed as separate attributes which are indexed based on the
1007// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
1008// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
1009// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
1010// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +03001011TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +03001012{
1013 if (!requestMultiviewExtension())
1014 {
1015 return;
1016 }
1017
Corentin Wallez02cd1522018-08-22 13:46:21 +02001018 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001019 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001020 if (IsWindows() && IsD3D11())
1021 {
1022 ignoreD3D11SDKLayersWarnings();
1023 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001024
Martin Radev553590a2017-07-31 16:40:39 +03001025 const std::string &vsSource =
1026 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001027 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001028 "layout(num_views = 2) in;\n"
1029 "in vec3 vPosition;\n"
1030 "in float offsetX;\n"
1031 "in float offsetY;\n"
1032 "void main()\n"
1033 "{\n"
1034 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001035 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001036 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
1037 " gl_Position.yzw = p.yzw;\n"
1038 "}\n";
1039
1040 const std::string &fsSource =
1041 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001042 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001043 "precision mediump float;\n"
1044 "out vec4 col;\n"
1045 "void main()\n"
1046 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001047 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001048 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +03001049
1050 const int kViewWidth = 4;
1051 const int kViewHeight = 4;
1052 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001053 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev553590a2017-07-31 16:40:39 +03001054 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev553590a2017-07-31 16:40:39 +03001055
1056 GLBuffer xOffsetVBO;
1057 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1058 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
1059 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
1060 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1061 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1062 glVertexAttribDivisor(xOffsetLoc, 3);
1063 glEnableVertexAttribArray(xOffsetLoc);
1064
1065 GLBuffer yOffsetVBO;
1066 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1067 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1068 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1069 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1070 glVertexAttribDivisor(yOffsetLoc, 1);
1071 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1072 glEnableVertexAttribArray(yOffsetLoc);
1073
Martin Radev67a8a012017-09-08 13:03:52 +03001074 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev553590a2017-07-31 16:40:39 +03001075 ASSERT_GL_NO_ERROR();
1076
Martin Radev67a8a012017-09-08 13:03:52 +03001077 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001078 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1079 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1080 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +03001081 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001082 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +03001083 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001084 for (int col = 0; col < 4; ++col)
1085 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001086 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0,
1087 expectedGreenChannel[view][row][col]),
Martin Radev3c25ad02017-08-22 17:36:53 +03001088 GetViewColor(col, row, view));
1089 }
Martin Radev553590a2017-07-31 16:40:39 +03001090 }
1091 }
1092}
1093
1094// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1095// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +03001096TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +03001097{
1098 if (!requestMultiviewExtension())
1099 {
1100 return;
1101 }
1102
Olli Etuaho4836acc2018-08-20 15:23:18 +03001103 updateFBOs(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +03001104
1105 // Create multiview program.
1106 const std::string &vs =
1107 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001108 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001109 "layout(num_views = 2) in;\n"
1110 "layout(location = 0) in vec2 vPosition;\n"
1111 "layout(location = 1) in float offsetX;\n"
1112 "void main()\n"
1113 "{\n"
1114 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1115 " p.x += offsetX;\n"
1116 " gl_Position = p;\n"
1117 "}\n";
1118
1119 const std::string &fs =
1120 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001121 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001122 "precision mediump float;\n"
1123 "out vec4 col;\n"
1124 "void main()\n"
1125 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001126 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001127 "}\n";
1128
1129 ANGLE_GL_PROGRAM(program, vs, fs);
1130
1131 const std::string &dummyVS =
1132 "#version 300 es\n"
1133 "layout(location = 0) in vec2 vPosition;\n"
1134 "layout(location = 1) in float offsetX;\n"
1135 "void main()\n"
1136 "{\n"
1137 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1138 "}\n";
1139
1140 const std::string &dummyFS =
1141 "#version 300 es\n"
1142 "precision mediump float;\n"
1143 "out vec4 col;\n"
1144 "void main()\n"
1145 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001146 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001147 "}\n";
1148
1149 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
1150
1151 GLBuffer xOffsetVBO;
1152 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1153 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1154 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1155 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1156
1157 GLBuffer vertexVBO;
1158 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1159 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1160 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1161 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1162
1163 GLVertexArray vao[2];
1164 for (size_t i = 0u; i < 2u; ++i)
1165 {
1166 glBindVertexArray(vao[i]);
1167
1168 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1169 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1170 glEnableVertexAttribArray(0);
1171
1172 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1173 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1174 glEnableVertexAttribArray(1);
1175 }
1176 ASSERT_GL_NO_ERROR();
1177
1178 glViewport(0, 0, 1, 1);
1179 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001180 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001181 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001182
1183 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1184 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1185 // bits are cleared.
1186 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001187 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1188 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001189 glBindVertexArray(vao[0]);
1190 glVertexAttribDivisor(1, 0);
1191 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1192 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001193 ASSERT_GL_NO_ERROR();
1194
1195 // Check that vertexAttribDivisor uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001196 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001197 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001198 glUseProgram(program);
1199 glVertexAttribDivisor(1, 1);
1200 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001201 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1202 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001203
1204 // Clear the buffers and propagate divisor to the driver.
1205 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1206 // dirty bits when useProgram is called.
1207 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001208 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1209 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001210 glVertexAttribDivisor(1, 1);
1211 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1212 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001213 ASSERT_GL_NO_ERROR();
1214
1215 // Check that useProgram uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001216 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001217 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001218 glUseProgram(program);
1219 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001220 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1221 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001222
1223 // We go through similar steps as before.
1224 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001225 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1226 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001227 glVertexAttribDivisor(1, 1);
1228 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1229 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001230 ASSERT_GL_NO_ERROR();
1231
1232 // Check that bindVertexArray uses the number of views to update the divisor.
1233 {
1234 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1235 // divisor for vao[1] only.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001236 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001237 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001238 glBindVertexArray(vao[1]);
1239 glUseProgram(program);
1240 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001241 glBindVertexArray(0);
1242 ASSERT_GL_NO_ERROR();
1243 }
1244 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1245 // adjusts the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001246 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001247 glBindVertexArray(vao[0]);
1248 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001249 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1250 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001251}
1252
Martin Radev0d671c92017-08-10 16:41:52 +03001253// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1254// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001255TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001256{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001257 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1258 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001259
1260 const std::string vsSource =
1261 "#version 300 es\n"
1262 "#extension GL_OVR_multiview : require\n"
1263 "layout(num_views = 2) in;\n"
1264 "in vec3 vPosition;\n"
1265 "void main()\n"
1266 "{\n"
1267 " gl_Position.x = 2.0;\n"
1268 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1269 "}\n";
1270
1271 const std::string fsSource =
1272 "#version 300 es\n"
1273 "#extension GL_OVR_multiview : require\n"
1274 "precision mediump float;\n"
1275 "out vec4 col;\n"
1276 "void main()\n"
1277 "{\n"
1278 " col = vec4(1,0,0,0);\n"
1279 "}\n";
1280 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001281 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001282
1283 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1284 ASSERT_GL_NO_ERROR();
1285 EXPECT_GL_FALSE(result);
1286}
1287
1288// Test that there are fragments passing the occlusion query if only view 0 can produce
1289// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001290TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001291{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001292 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1293 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001294
1295 const std::string vsSource =
1296 "#version 300 es\n"
1297 "#extension GL_OVR_multiview : require\n"
1298 "layout(num_views = 2) in;\n"
1299 "in vec3 vPosition;\n"
1300 "void main()\n"
1301 "{\n"
1302 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1303 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1304 "}\n";
1305
1306 const std::string fsSource =
1307 "#version 300 es\n"
1308 "#extension GL_OVR_multiview : require\n"
1309 "precision mediump float;\n"
1310 "out vec4 col;\n"
1311 "void main()\n"
1312 "{\n"
1313 " col = vec4(1,0,0,0);\n"
1314 "}\n";
1315 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001316 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001317
1318 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1319 ASSERT_GL_NO_ERROR();
1320 EXPECT_GL_TRUE(result);
1321}
1322
1323// Test that there are fragments passing the occlusion query if only view 1 can produce
1324// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001325TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001326{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001327 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1328 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001329
1330 const std::string vsSource =
1331 "#version 300 es\n"
1332 "#extension GL_OVR_multiview : require\n"
1333 "layout(num_views = 2) in;\n"
1334 "in vec3 vPosition;\n"
1335 "void main()\n"
1336 "{\n"
1337 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1338 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1339 "}\n";
1340
1341 const std::string fsSource =
1342 "#version 300 es\n"
1343 "#extension GL_OVR_multiview : require\n"
1344 "precision mediump float;\n"
1345 "out vec4 col;\n"
1346 "void main()\n"
1347 "{\n"
1348 " col = vec4(1,0,0,0);\n"
1349 "}\n";
1350 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001351 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001352
1353 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1354 ASSERT_GL_NO_ERROR();
1355 EXPECT_GL_TRUE(result);
1356}
1357
Martin Radev41ac68e2017-06-06 12:16:58 +03001358// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1359// compiles and links without an error.
1360TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1361{
1362 if (!requestMultiviewExtension())
1363 {
1364 return;
1365 }
1366
1367 const std::string vsSource =
1368 "#version 300 es\n"
1369 "#extension GL_OVR_multiview : require\n"
1370 "layout(num_views = 2) in;\n"
1371 "void main()\n"
1372 "{\n"
1373 "}\n";
1374
1375 const std::string fsSource =
1376 "#version 300 es\n"
1377 "#extension GL_OVR_multiview : require\n"
1378 "precision mediump float;\n"
1379 "void main()\n"
1380 "{\n"
1381 "}\n";
1382
1383 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1384 glUseProgram(program);
1385
1386 EXPECT_GL_NO_ERROR();
1387}
1388
1389// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1390// without an error.
1391TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1392{
1393 if (!requestMultiviewExtension())
1394 {
1395 return;
1396 }
1397
1398 const std::string vsSource =
1399 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001400 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001401 "layout(num_views = 2) in;\n"
1402 "void main()\n"
1403 "{\n"
1404 " if (gl_ViewID_OVR == 0u) {\n"
1405 " gl_Position = vec4(1,0,0,1);\n"
1406 " } else {\n"
1407 " gl_Position = vec4(-1,0,0,1);\n"
1408 " }\n"
1409 "}\n";
1410
1411 const std::string fsSource =
1412 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001413 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001414 "precision mediump float;\n"
1415 "void main()\n"
1416 "{\n"
1417 "}\n";
1418
1419 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1420 glUseProgram(program);
1421
1422 EXPECT_GL_NO_ERROR();
1423}
1424
1425// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1426// without an error.
1427TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1428{
1429 if (!requestMultiviewExtension())
1430 {
1431 return;
1432 }
1433
1434 const std::string vsSource =
1435 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001436 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001437 "layout(num_views = 2) in;\n"
1438 "void main()\n"
1439 "{\n"
1440 "}\n";
1441
1442 const std::string fsSource =
1443 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001444 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001445 "precision mediump float;\n"
1446 "out vec4 col;\n"
1447 "void main()\n"
1448 "{\n"
1449 " if (gl_ViewID_OVR == 0u) {\n"
1450 " col = vec4(1,0,0,1);\n"
1451 " } else {\n"
1452 " col = vec4(-1,0,0,1);\n"
1453 " }\n"
1454 "}\n";
1455
1456 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1457 glUseProgram(program);
1458
1459 EXPECT_GL_NO_ERROR();
1460}
1461
Martin Radev61bd9992017-08-11 13:10:55 +03001462// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001463TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001464{
1465 if (!requestMultiviewExtension())
1466 {
1467 return;
1468 }
1469
Geoff Lang25858162017-11-06 11:25:58 -05001470 // Test failing on P400 graphics card (anglebug.com/2228)
1471 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1472
Martin Radev61bd9992017-08-11 13:10:55 +03001473 const std::string vsSource =
1474 "#version 300 es\n"
1475 "#extension GL_OVR_multiview : require\n"
1476 "layout(num_views = 2) in;\n"
1477 "layout(location=0) in vec2 vPosition;\n"
1478 "void main()\n"
1479 "{\n"
1480 " gl_PointSize = 1.0;\n"
1481 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1482 "}\n";
1483
1484 const std::string fsSource =
1485 "#version 300 es\n"
1486 "#extension GL_OVR_multiview : require\n"
1487 "precision mediump float;\n"
1488 "out vec4 col;\n"
1489 "void main()\n"
1490 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001491 " col = vec4(0,1,0,1);\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001492 "}\n";
1493 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1494 glUseProgram(program);
1495
Martin Radev3c25ad02017-08-22 17:36:53 +03001496 const int kViewWidth = 4;
1497 const int kViewHeight = 2;
1498 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001499 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001500
1501 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1502 std::vector<Vector2> vertexDataInClipSpace =
1503 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1504 setupGeometry(vertexDataInClipSpace);
1505
1506 glDrawArrays(GL_POINTS, 0, 2);
1507
Martin Radev67a8a012017-09-08 13:03:52 +03001508 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001509 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001510 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001511}
1512
1513// The test checks that GL_LINES is correctly rendered.
1514// The behavior of this test is not guaranteed by the spec:
1515// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1516// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1517// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1518// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001519TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001520{
1521 if (!requestMultiviewExtension())
1522 {
1523 return;
1524 }
1525
Martin Radevced5c862017-08-17 16:05:29 +03001526 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001527 ASSERT_NE(program, 0u);
1528 glUseProgram(program);
1529 ASSERT_GL_NO_ERROR();
1530
Martin Radev3c25ad02017-08-22 17:36:53 +03001531 const int kViewWidth = 4;
1532 const int kViewHeight = 2;
1533 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001534 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001535
1536 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1537 std::vector<Vector2> vertexDataInClipSpace =
1538 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1539 setupGeometry(vertexDataInClipSpace);
1540
1541 glDrawArrays(GL_LINES, 0, 2);
1542
Martin Radev67a8a012017-09-08 13:03:52 +03001543 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001544 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001545 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001546
1547 glDeleteProgram(program);
1548}
1549
1550// The test checks that GL_LINE_STRIP is correctly rendered.
1551// The behavior of this test is not guaranteed by the spec:
1552// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1553// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1554// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1555// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001556TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001557{
1558 if (!requestMultiviewExtension())
1559 {
1560 return;
1561 }
1562
Martin Radevced5c862017-08-17 16:05:29 +03001563 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001564 ASSERT_NE(program, 0u);
1565 glUseProgram(program);
1566 ASSERT_GL_NO_ERROR();
1567
Martin Radev3c25ad02017-08-22 17:36:53 +03001568 const int kViewWidth = 4;
1569 const int kViewHeight = 2;
1570 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001571 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001572
1573 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1574 std::vector<Vector2> vertexDataInClipSpace =
1575 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1576 setupGeometry(vertexDataInClipSpace);
1577
1578 glDrawArrays(GL_LINE_STRIP, 0, 3);
1579
Martin Radev67a8a012017-09-08 13:03:52 +03001580 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001581 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001582 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001583
1584 glDeleteProgram(program);
1585}
1586
1587// The test checks that GL_LINE_LOOP is correctly rendered.
1588// The behavior of this test is not guaranteed by the spec:
1589// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1590// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1591// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1592// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001593TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001594{
1595 if (!requestMultiviewExtension())
1596 {
1597 return;
1598 }
1599
Martin Radevced5c862017-08-17 16:05:29 +03001600 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001601 ASSERT_NE(program, 0u);
1602 glUseProgram(program);
1603 ASSERT_GL_NO_ERROR();
1604
Martin Radev3c25ad02017-08-22 17:36:53 +03001605 const int kViewWidth = 4;
1606 const int kViewHeight = 4;
1607 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001608 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001609
1610 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1611 Vector2I(0, 3)};
1612 std::vector<Vector2> vertexDataInClipSpace =
1613 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1614 setupGeometry(vertexDataInClipSpace);
1615
1616 glDrawArrays(GL_LINE_LOOP, 0, 4);
1617
Martin Radev67a8a012017-09-08 13:03:52 +03001618 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001619 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1620 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001621 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001622
1623 glDeleteProgram(program);
1624}
1625
1626// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001627TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001628{
1629 if (!requestMultiviewExtension())
1630 {
1631 return;
1632 }
1633
Martin Radevced5c862017-08-17 16:05:29 +03001634 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001635 ASSERT_NE(program, 0u);
1636 glUseProgram(program);
1637 ASSERT_GL_NO_ERROR();
1638
1639 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1640 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1641 setupGeometry(vertexDataInClipSpace);
1642
Martin Radev3c25ad02017-08-22 17:36:53 +03001643 const int kViewWidth = 2;
1644 const int kViewHeight = 2;
1645 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001646 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001647
1648 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1649
Martin Radev67a8a012017-09-08 13:03:52 +03001650 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1651 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1652 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001653
1654 glDeleteProgram(program);
1655}
1656
1657// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001658TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001659{
1660 if (!requestMultiviewExtension())
1661 {
1662 return;
1663 }
1664
Martin Radevced5c862017-08-17 16:05:29 +03001665 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001666 ASSERT_NE(program, 0u);
1667 glUseProgram(program);
1668 ASSERT_GL_NO_ERROR();
1669
1670 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1671 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1672 setupGeometry(vertexDataInClipSpace);
1673
Martin Radev3c25ad02017-08-22 17:36:53 +03001674 const int kViewWidth = 2;
1675 const int kViewHeight = 2;
1676 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001677 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001678
1679 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1680
Martin Radev67a8a012017-09-08 13:03:52 +03001681 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1682 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1683 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001684
1685 glDeleteProgram(program);
1686}
1687
1688// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1689// bounds. The test does not rely on the actual line width being greater than 1.0.
Martin Radev3c25ad02017-08-22 17:36:53 +03001690TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
Martin Radev61bd9992017-08-11 13:10:55 +03001691{
1692 if (!requestMultiviewExtension())
1693 {
1694 return;
1695 }
1696
Olli Etuaho9259fd02018-08-22 12:12:00 +03001697 GLTexture colorTexture;
Martin Radev61bd9992017-08-11 13:10:55 +03001698
Olli Etuaho9259fd02018-08-22 12:12:00 +03001699 CreateMultiviewBackingTextures(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, 2, 1, 2,
1700 colorTexture, 0u, 0u);
1701
1702 GLFramebuffer drawFramebuffer;
1703 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFramebuffer);
Martin Radev61bd9992017-08-11 13:10:55 +03001704 GLint viewportOffsets[4] = {1, 0, 3, 0};
1705 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
Olli Etuaho9259fd02018-08-22 12:12:00 +03001706 colorTexture, 0, 2, &viewportOffsets[0]);
1707
1708 GLFramebuffer readFramebuffer;
1709 glBindFramebuffer(GL_READ_FRAMEBUFFER, readFramebuffer);
1710 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture,
1711 0);
1712
1713 ASSERT_GL_NO_ERROR();
Martin Radev61bd9992017-08-11 13:10:55 +03001714
1715 glViewport(0, 0, 1, 1);
1716 glScissor(0, 0, 1, 1);
1717 glEnable(GL_SCISSOR_TEST);
1718
1719 const std::string vsSource =
1720 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001721 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001722 "layout(num_views = 2) in;\n"
1723 "layout(location=0) in vec2 vPosition;\n"
1724 "void main()\n"
1725 "{\n"
1726 " gl_PointSize = 10.0;\n"
1727 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1728 "}\n";
1729
1730 const std::string fsSource =
1731 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001732 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001733 "precision mediump float;\n"
1734 "out vec4 col;\n"
1735 "void main()\n"
1736 "{\n"
1737 " if (gl_ViewID_OVR == 0u) {\n"
1738 " col = vec4(1,0,0,1);\n"
1739 " } else {\n"
1740 " col = vec4(0,1,0,1);\n"
1741 " }\n"
1742 "}\n";
1743 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1744 glUseProgram(program);
1745
1746 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1747 const std::vector<Vector2> &vertexDataInClipSpace =
1748 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001749
1750 GLBuffer vbo;
1751 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1752 glBufferData(GL_ARRAY_BUFFER, vertexDataInClipSpace.size() * sizeof(Vector2),
1753 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1754 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -05001755 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +03001756
1757 // Test rendering points.
1758 {
1759 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1760 glDrawArrays(GL_POINTS, 0, 2);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001761 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001762 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001763 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001764 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1765 }
1766
1767 // Test rendering lines.
1768 {
1769 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1770 glLineWidth(10.f);
1771 glDrawArrays(GL_LINES, 0, 2);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001772 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001773 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001774 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001775 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1776 }
1777}
1778
Martin Radev0abb7a22017-08-28 15:34:45 +03001779// Verify that re-linking a program adjusts the attribute divisor.
1780// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1781// to each other. The quads' position and color depend on the corresponding attribute divisors.
1782TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1783{
1784 if (!requestMultiviewExtension())
1785 {
1786 return;
1787 }
1788
Corentin Wallez02cd1522018-08-22 13:46:21 +02001789 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001790 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001791 if (IsWindows() && IsD3D11())
1792 {
1793 ignoreD3D11SDKLayersWarnings();
1794 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001795
Martin Radev0abb7a22017-08-28 15:34:45 +03001796 const int kViewWidth = 4;
1797 const int kViewHeight = 1;
1798 const int kNumViews = 2;
1799
1800 const std::string &fsSource =
1801 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001802 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001803 "precision mediump float;\n"
1804 "in vec4 oColor;\n"
1805 "out vec4 col;\n"
1806 "void main()\n"
1807 "{\n"
1808 " col = oColor;\n"
1809 "}\n";
1810
1811 auto generateVertexShaderSource = [](int numViews) -> std::string {
1812 std::string source =
1813 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001814 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001815 "layout(num_views = " +
1816 ToString(numViews) +
1817 ") in;\n"
1818 "in vec3 vPosition;\n"
1819 "in float vOffsetX;\n"
1820 "in vec4 vColor;\n"
1821 "out vec4 oColor;\n"
1822 "void main()\n"
1823 "{\n"
1824 " vec4 p = vec4(vPosition, 1.);\n"
1825 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1826 " oColor = vColor;\n"
1827 " gl_Position = p;\n"
1828 "}\n";
1829 return source;
1830 };
1831
1832 std::string vsSource = generateVertexShaderSource(kNumViews);
1833 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1834 glUseProgram(program);
1835
1836 GLint positionLoc;
1837 GLBuffer xOffsetVBO;
1838 GLint xOffsetLoc;
1839 GLBuffer colorVBO;
1840 GLint colorLoc;
1841
1842 {
1843 // Initialize buffers and setup attributes.
1844 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1845 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1846 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1847 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1848 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1849 glVertexAttribDivisor(xOffsetLoc, 1);
1850 glEnableVertexAttribArray(xOffsetLoc);
1851
1852 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1853 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1854 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1855 colorLoc = glGetAttribLocation(program, "vColor");
1856 glVertexAttribDivisor(colorLoc, 2);
1857 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1858 glEnableVertexAttribArray(colorLoc);
1859
1860 positionLoc = glGetAttribLocation(program, "vPosition");
1861 }
1862
1863 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001864 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001865
Martin Radev67a8a012017-09-08 13:03:52 +03001866 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001867 ASSERT_GL_NO_ERROR();
1868
1869 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1870 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1871 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1872 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1873 }
1874
1875 {
1876 const int kNewNumViews = 3;
1877 vsSource = generateVertexShaderSource(kNewNumViews);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001878 updateFBOs(kViewWidth, kViewHeight, kNewNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001879
1880 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
1881 ASSERT_NE(0u, vs);
1882 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
1883 ASSERT_NE(0u, fs);
1884
1885 GLint numAttachedShaders = 0;
1886 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1887
1888 GLuint attachedShaders[2] = {0u};
1889 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1890 for (int i = 0; i < 2; ++i)
1891 {
1892 glDetachShader(program, attachedShaders[i]);
1893 }
1894
1895 glAttachShader(program, vs);
1896 glDeleteShader(vs);
1897
1898 glAttachShader(program, fs);
1899 glDeleteShader(fs);
1900
1901 glBindAttribLocation(program, positionLoc, "vPosition");
1902 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1903 glBindAttribLocation(program, colorLoc, "vColor");
1904
1905 glLinkProgram(program);
1906
Martin Radev67a8a012017-09-08 13:03:52 +03001907 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001908 ASSERT_GL_NO_ERROR();
1909
1910 for (int i = 0; i < kNewNumViews; ++i)
1911 {
1912 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1913 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1914 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1915 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1916 }
1917 }
1918}
1919
Martin Radevced5c862017-08-17 16:05:29 +03001920// Test that useProgram applies the number of views in computing the final value of the attribute
1921// divisor.
1922TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1923{
1924 if (!requestMultiviewExtension())
1925 {
1926 return;
1927 }
1928
Geoff Lang25858162017-11-06 11:25:58 -05001929 // Test failing on P400 graphics card (anglebug.com/2228)
1930 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1931
Olli Etuaho44ae8992018-08-20 15:37:09 +03001932 // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
1933 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001934 if (IsWindows() && IsD3D11())
1935 {
1936 ignoreD3D11SDKLayersWarnings();
1937 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001938
Martin Radevced5c862017-08-17 16:05:29 +03001939 GLVertexArray vao;
1940 glBindVertexArray(vao);
1941 GLBuffer vbo;
1942 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1943 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
1944 Vector2I(3, 0)};
1945 std::vector<Vector2> vertexDataInClipSpace =
1946 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
1947 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
1948 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
1949 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1950 glEnableVertexAttribArray(0);
1951 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
1952 glVertexAttribDivisor(0, 1);
1953 ASSERT_GL_NO_ERROR();
1954
1955 // Create a program and fbo with N views and draw N instances of a point horizontally.
1956 for (int numViews = 2; numViews <= 4; ++numViews)
1957 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001958 updateFBOs(4, 1, numViews);
Martin Radevced5c862017-08-17 16:05:29 +03001959 ASSERT_GL_NO_ERROR();
1960
1961 GLuint program = CreateSimplePassthroughProgram(numViews);
1962 ASSERT_NE(program, 0u);
1963 glUseProgram(program);
1964 ASSERT_GL_NO_ERROR();
1965
1966 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
1967
1968 for (int view = 0; view < numViews; ++view)
1969 {
1970 for (int j = 0; j < numViews; ++j)
1971 {
Martin Radev67a8a012017-09-08 13:03:52 +03001972 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03001973 }
1974 for (int j = numViews; j < 4; ++j)
1975 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001976 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03001977 }
1978 }
1979
1980 glDeleteProgram(program);
1981 }
1982}
1983
Martin Radev72b4e1e2017-08-31 15:42:56 +03001984// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
1985TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
1986{
1987 if (!requestMultiviewExtension())
1988 {
1989 return;
1990 }
1991
1992 const std::string vsSource =
1993 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001994 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001995 "layout(num_views = 3) in;\n"
1996 "in vec3 vPosition;\n"
1997 "void main()\n"
1998 "{\n"
1999 " gl_Position = vec4(vPosition, 1.);\n"
2000 "}\n";
2001
2002 const std::string fsSource =
2003 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002004 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002005 "precision mediump float;\n"
2006 "out vec4 col;\n"
2007 "void main()\n"
2008 "{\n"
2009 " if (gl_ViewID_OVR == 0u) {\n"
2010 " col = vec4(1,0,0,1);\n"
2011 " } else if (gl_ViewID_OVR == 1u) {\n"
2012 " col = vec4(0,1,0,1);\n"
2013 " } else if (gl_ViewID_OVR == 2u) {\n"
2014 " col = vec4(0,0,1,1);\n"
2015 " } else {\n"
2016 " col = vec4(0,0,0,0);\n"
2017 " }\n"
2018 "}\n";
2019
Olli Etuaho4836acc2018-08-20 15:23:18 +03002020 updateFBOs(1, 1, 3);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002021 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002022
2023 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2024 ASSERT_GL_NO_ERROR();
2025
2026 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2027 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2028 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
2029}
2030
2031// The test checks that the inactive layers of a 2D texture array are not written to by a
2032// multi-view program.
2033TEST_P(MultiviewLayeredRenderTest, RenderToSubrageOfLayers)
2034{
2035 if (!requestMultiviewExtension())
2036 {
2037 return;
2038 }
2039
2040 const std::string vsSource =
2041 "#version 300 es\n"
2042 "#extension GL_OVR_multiview : require\n"
2043 "layout(num_views = 2) in;\n"
2044 "in vec3 vPosition;\n"
2045 "void main()\n"
2046 "{\n"
2047 " gl_Position = vec4(vPosition, 1.);\n"
2048 "}\n";
2049
2050 const std::string fsSource =
2051 "#version 300 es\n"
2052 "#extension GL_OVR_multiview : require\n"
2053 "precision mediump float;\n"
2054 "out vec4 col;\n"
2055 "void main()\n"
2056 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002057 " col = vec4(0,1,0,1);\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002058 "}\n";
2059
Olli Etuaho4836acc2018-08-20 15:23:18 +03002060 updateFBOs(1, 1, 2, 4, 1);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002061 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002062
2063 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2064 ASSERT_GL_NO_ERROR();
2065
2066 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +03002067 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2068 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002069 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
2070}
2071
Martin Radevc1d4e552017-08-21 12:01:10 +03002072// The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
2073// potential bugs if the view is selected in the VS. The test contains a program in which the
2074// gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
2075// fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
2076// never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
2077// green for view 1.
2078TEST_P(MultiviewRenderTest, FlatInterpolation)
Martin Radev3c25ad02017-08-22 17:36:53 +03002079{
Martin Radevc1d4e552017-08-21 12:01:10 +03002080 if (!requestMultiviewExtension())
2081 {
2082 return;
2083 }
2084
2085 const std::string vsSource =
2086 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002087 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002088 "layout(num_views = 2) in;\n"
2089 "in vec3 vPosition;\n"
2090 "flat out int oInstanceID;\n"
2091 "void main()\n"
2092 "{\n"
2093 " gl_Position = vec4(vPosition, 1.);\n"
2094 " oInstanceID = gl_InstanceID;\n"
2095 "}\n";
2096
2097 const std::string fsSource =
2098 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002099 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002100 "precision mediump float;\n"
2101 "flat in int oInstanceID;\n"
2102 "out vec4 col;\n"
2103 "void main()\n"
2104 "{\n"
2105 " if (oInstanceID < 0) {\n"
2106 " discard;\n"
2107 " }\n"
2108 " if (gl_ViewID_OVR == 0u) {\n"
2109 " col = vec4(1,0,0,1);\n"
2110 " } else {\n"
2111 " col = vec4(0,1,0,1);\n"
2112 " }\n"
2113 "}\n";
2114
Olli Etuaho4836acc2018-08-20 15:23:18 +03002115 updateFBOs(1, 1, 2);
Martin Radevc1d4e552017-08-21 12:01:10 +03002116 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2117
2118 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2119 ASSERT_GL_NO_ERROR();
2120
2121 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2122 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +03002123}
2124
Olli Etuaho604d8732018-07-20 11:02:43 +03002125// This test assigns gl_ViewID_OVR to a flat int varying and then sets the color based on that
2126// varying in the fragment shader.
2127TEST_P(MultiviewRenderTest, FlatInterpolation2)
2128{
2129 if (!requestMultiviewExtension())
2130 {
2131 return;
2132 }
2133
2134 const std::string vsSource =
2135 "#version 300 es\n"
2136 "#extension GL_OVR_multiview : require\n"
2137 "layout(num_views = 2) in;\n"
2138 "in vec3 vPosition;\n"
2139 "flat out int flatVarying;\n"
2140 "void main()\n"
2141 "{\n"
2142 " gl_Position = vec4(vPosition, 1.);\n"
2143 " flatVarying = int(gl_ViewID_OVR);\n"
2144 "}\n";
2145
2146 const std::string fsSource =
2147 "#version 300 es\n"
2148 "#extension GL_OVR_multiview : require\n"
2149 "precision mediump float;\n"
2150 "flat in int flatVarying;\n"
2151 "out vec4 col;\n"
2152 "void main()\n"
2153 "{\n"
2154 " if (flatVarying == 0) {\n"
2155 " col = vec4(1,0,0,1);\n"
2156 " } else {\n"
2157 " col = vec4(0,1,0,1);\n"
2158 " }\n"
2159 "}\n";
2160
Olli Etuaho4836acc2018-08-20 15:23:18 +03002161 updateFBOs(1, 1, 2);
Olli Etuaho604d8732018-07-20 11:02:43 +03002162 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2163
2164 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2165 ASSERT_GL_NO_ERROR();
2166
2167 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2168 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2169}
2170
Martin Radev265a6d42017-09-12 16:51:37 +03002171// The test is added to cover a bug which resulted in the viewport/scissor and viewport offsets not
2172// being correctly applied.
2173TEST_P(MultiviewSideBySideRenderTest, ViewportOffsetsAppliedBugCoverage)
2174{
2175 if (!requestMultiviewExtension())
2176 {
2177 return;
2178 }
2179
Olli Etuaho4836acc2018-08-20 15:23:18 +03002180 updateFBOs(1, 1, 2);
Martin Radev265a6d42017-09-12 16:51:37 +03002181
2182 // Create multiview program.
2183 const std::string &vs =
2184 "#version 300 es\n"
2185 "#extension GL_OVR_multiview : require\n"
2186 "layout(num_views = 2) in;\n"
2187 "layout(location = 0) in vec3 vPosition;\n"
2188 "void main()\n"
2189 "{\n"
2190 " gl_Position = vec4(vPosition, 1.0);\n"
2191 "}\n";
2192
2193 const std::string &fs =
2194 "#version 300 es\n"
2195 "#extension GL_OVR_multiview : require\n"
2196 "precision mediump float;\n"
2197 "out vec4 col;\n"
2198 "void main()\n"
2199 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002200 " col = vec4(0,1,0,1);\n"
Martin Radev265a6d42017-09-12 16:51:37 +03002201 "}\n";
2202
2203 ANGLE_GL_PROGRAM(program, vs, fs);
2204
2205 glViewport(0, 0, 1, 1);
2206 glScissor(0, 0, 1, 1);
2207 glEnable(GL_SCISSOR_TEST);
2208 glClearColor(0, 0, 0, 1);
2209
2210 // Bind the default FBO and make sure that the state is synchronized.
2211 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
2212 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2213 ASSERT_GL_NO_ERROR();
2214
2215 // Draw and check that both views are rendered to.
Olli Etuaho4836acc2018-08-20 15:23:18 +03002216 bindMemberDrawFramebuffer();
Martin Radev265a6d42017-09-12 16:51:37 +03002217 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev67a8a012017-09-08 13:03:52 +03002218
Martin Radev265a6d42017-09-12 16:51:37 +03002219 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
Martin Radev67a8a012017-09-08 13:03:52 +03002220 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
2221 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev265a6d42017-09-12 16:51:37 +03002222}
2223
Olli Etuahof26b27e2018-08-17 11:01:19 +03002224MultiviewRenderTestParams SideBySideVertexShaderOpenGL(GLint majorVersion = 3,
2225 GLint minorVersion = 0)
Martin Radev3c25ad02017-08-22 17:36:53 +03002226{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002227 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE,
2228 VertexShaderOpenGL(majorVersion, minorVersion));
Martin Radev3c25ad02017-08-22 17:36:53 +03002229}
2230
Olli Etuahof26b27e2018-08-17 11:01:19 +03002231MultiviewRenderTestParams LayeredVertexShaderOpenGL()
Martin Radev3c25ad02017-08-22 17:36:53 +03002232{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002233 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
2234 VertexShaderOpenGL(3, 0));
Martin Radev3c25ad02017-08-22 17:36:53 +03002235}
2236
Olli Etuahof26b27e2018-08-17 11:01:19 +03002237MultiviewRenderTestParams SideBySideGeomShaderD3D11()
Martin Radev72b4e1e2017-08-31 15:42:56 +03002238{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002239 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE,
2240 GeomShaderD3D11(3, 0));
Martin Radevc1d4e552017-08-21 12:01:10 +03002241}
2242
Olli Etuahof26b27e2018-08-17 11:01:19 +03002243MultiviewRenderTestParams LayeredGeomShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002244{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002245 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, GeomShaderD3D11(3, 0));
Martin Radevc1d4e552017-08-21 12:01:10 +03002246}
2247
Olli Etuahof26b27e2018-08-17 11:01:19 +03002248MultiviewRenderTestParams SideBySideVertexShaderD3D11(GLint majorVersion = 3,
2249 GLint minorVersion = 0)
Martin Radevc1d4e552017-08-21 12:01:10 +03002250{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002251 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE,
2252 VertexShaderD3D11(majorVersion, minorVersion));
Martin Radevc1d4e552017-08-21 12:01:10 +03002253}
2254
Olli Etuahof26b27e2018-08-17 11:01:19 +03002255MultiviewRenderTestParams LayeredVertexShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002256{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002257 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
2258 VertexShaderD3D11(3, 0));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002259}
2260
Jamie Madill04c084d2018-08-08 15:49:28 -04002261ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest,
Olli Etuaho44ae8992018-08-20 15:37:09 +03002262 VertexShaderOpenGL(3, 1),
2263 VertexShaderD3D11(3, 1));
Martin Radevced5c862017-08-17 16:05:29 +03002264ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002265 SideBySideVertexShaderOpenGL(),
2266 LayeredVertexShaderOpenGL(),
2267 SideBySideGeomShaderD3D11(),
2268 SideBySideVertexShaderD3D11(),
2269 LayeredGeomShaderD3D11(),
2270 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002271ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002272 SideBySideVertexShaderOpenGL(),
2273 LayeredVertexShaderOpenGL(),
2274 SideBySideGeomShaderD3D11(),
2275 SideBySideVertexShaderD3D11(),
2276 LayeredGeomShaderD3D11(),
2277 LayeredVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002278ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002279 SideBySideVertexShaderOpenGL(),
2280 LayeredVertexShaderOpenGL(),
2281 SideBySideGeomShaderD3D11(),
2282 SideBySideVertexShaderD3D11(),
2283 LayeredGeomShaderD3D11(),
2284 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002285ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
Olli Etuaho4bcaf992018-08-17 17:18:28 +03002286 VertexShaderOpenGL(3, 0),
2287 GeomShaderD3D11(3, 0),
2288 VertexShaderD3D11(3, 0));
Martin Radevced5c862017-08-17 16:05:29 +03002289ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002290 SideBySideVertexShaderOpenGL(),
2291 LayeredVertexShaderOpenGL(),
2292 SideBySideGeomShaderD3D11(),
2293 SideBySideVertexShaderD3D11(),
2294 LayeredGeomShaderD3D11(),
2295 LayeredVertexShaderD3D11());
Jamie Madill04c084d2018-08-08 15:49:28 -04002296ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest,
2297 VertexShaderOpenGL(3, 0),
2298 GeomShaderD3D11(3, 0));
2299ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, VertexShaderOpenGL(3, 0), GeomShaderD3D11(3, 0));