blob: 1e855c00ac3a8e2852d8c2e15a14c56bfe42bb1f [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
Martin Radev8f276e22017-05-30 12:05:52 +0300104 // Create color and depth textures.
Martin Radev3c25ad02017-08-22 17:36:53 +0300105 switch (mMultiviewLayout)
Martin Radev8f276e22017-05-30 12:05:52 +0300106 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300107 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
108 {
109 int textureWidth = viewWidth * numViews;
110 glBindTexture(GL_TEXTURE_2D, mColorTexture);
111 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, height, 0, GL_RGBA,
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500112 GL_UNSIGNED_BYTE, nullptr);
Martin Radev3c25ad02017-08-22 17:36:53 +0300113 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
114 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
115
116 glBindTexture(GL_TEXTURE_2D, mDepthTexture);
117 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, textureWidth, height, 0,
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500118 GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
Martin Radev3c25ad02017-08-22 17:36:53 +0300119 glBindTexture(GL_TEXTURE_2D, 0);
120 break;
121 }
122 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
123 glBindTexture(GL_TEXTURE_2D_ARRAY, mColorTexture);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300124 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, viewWidth, height, numLayers, 0,
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500125 GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
Martin Radev3c25ad02017-08-22 17:36:53 +0300126 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
127 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
128
129 glBindTexture(GL_TEXTURE_2D_ARRAY, mDepthTexture);
130 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, viewWidth, height,
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500131 numLayers, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
Martin Radev3c25ad02017-08-22 17:36:53 +0300132 glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
133 break;
134 default:
135 UNREACHABLE();
Martin Radev8f276e22017-05-30 12:05:52 +0300136 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300137 ASSERT_GL_NO_ERROR();
138
Olli Etuaho44ae8992018-08-20 15:37:09 +0300139 glGenFramebuffers(1, &mDrawFramebuffer);
140
Martin Radev3c25ad02017-08-22 17:36:53 +0300141 // Create draw framebuffer to be used for multiview rendering.
142 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
143 switch (mMultiviewLayout)
144 {
145 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
146 {
147 std::vector<GLint> viewportOffsets(numViews * 2);
148 for (int i = 0u; i < numViews; ++i)
149 {
150 viewportOffsets[i * 2] = i * viewWidth;
151 viewportOffsets[i * 2 + 1] = 0;
152 }
153 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER,
154 GL_COLOR_ATTACHMENT0, mColorTexture, 0,
155 numViews, &viewportOffsets[0]);
156 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER,
157 GL_DEPTH_ATTACHMENT, mDepthTexture, 0,
158 numViews, &viewportOffsets[0]);
159 break;
160 }
161 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
162 glFramebufferTextureMultiviewLayeredANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
Martin Radev72b4e1e2017-08-31 15:42:56 +0300163 mColorTexture, 0, baseViewIndex,
164 numViews);
Martin Radev3c25ad02017-08-22 17:36:53 +0300165 glFramebufferTextureMultiviewLayeredANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
Martin Radev72b4e1e2017-08-31 15:42:56 +0300166 mDepthTexture, 0, baseViewIndex,
167 numViews);
Martin Radev3c25ad02017-08-22 17:36:53 +0300168 break;
169 default:
170 UNREACHABLE();
171 }
Martin Radev8f276e22017-05-30 12:05:52 +0300172
173 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
174 glDrawBuffers(1, DrawBuffers);
175 ASSERT_GL_NO_ERROR();
176 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
177
178 // Create read framebuffer to be used to retrieve the pixel information for testing
179 // purposes.
Martin Radev3c25ad02017-08-22 17:36:53 +0300180 switch (mMultiviewLayout)
181 {
182 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
183 mReadFramebuffer.resize(1);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300184 glGenFramebuffers(1, mReadFramebuffer.data());
Martin Radev3c25ad02017-08-22 17:36:53 +0300185 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
186 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
187 mColorTexture, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300188 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
189 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300190 break;
191 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
Martin Radev72b4e1e2017-08-31 15:42:56 +0300192 mReadFramebuffer.resize(numLayers);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300193 glGenFramebuffers(mReadFramebuffer.size(), mReadFramebuffer.data());
Martin Radev72b4e1e2017-08-31 15:42:56 +0300194 for (int i = 0; i < numLayers; ++i)
Martin Radev3c25ad02017-08-22 17:36:53 +0300195 {
Martin Radev72b4e1e2017-08-31 15:42:56 +0300196 glBindFramebuffer(GL_FRAMEBUFFER, mReadFramebuffer[i]);
197 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mColorTexture,
198 0, i);
199 glClearColor(0, 0, 0, 0);
200 glClear(GL_COLOR_BUFFER_BIT);
201 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
202 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300203 }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300204 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
Martin Radev3c25ad02017-08-22 17:36:53 +0300205 break;
206 default:
207 UNREACHABLE();
208 }
Martin Radev8f276e22017-05-30 12:05:52 +0300209
210 // Clear the buffers.
Martin Radev3c25ad02017-08-22 17:36:53 +0300211 glViewport(0, 0, viewWidth, height);
212 if (mMultiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
213 {
214 // Enable the scissor test only for side-by-side framebuffers.
215 glEnable(GL_SCISSOR_TEST);
216 glScissor(0, 0, viewWidth, height);
217 }
Martin Radev61bd9992017-08-11 13:10:55 +0300218 glClearColor(0, 0, 0, 1);
Martin Radev8f276e22017-05-30 12:05:52 +0300219 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev3c25ad02017-08-22 17:36:53 +0300220 }
Martin Radev8f276e22017-05-30 12:05:52 +0300221
Olli Etuaho4836acc2018-08-20 15:23:18 +0300222 void updateFBOs(int viewWidth, int height, int numViews)
Martin Radev72b4e1e2017-08-31 15:42:56 +0300223 {
Olli Etuaho4836acc2018-08-20 15:23:18 +0300224 updateFBOs(viewWidth, height, numViews, numViews, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300225 }
226
Olli Etuaho4836acc2018-08-20 15:23:18 +0300227 void bindMemberDrawFramebuffer() { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer); }
228
Martin Radev3c25ad02017-08-22 17:36:53 +0300229 GLColor GetViewColor(int x, int y, int view)
230 {
231 switch (mMultiviewLayout)
232 {
233 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
234 return ReadColor(view * mViewWidth + x, y);
235 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
236 ASSERT(static_cast<size_t>(view) < mReadFramebuffer.size());
237 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
238 return ReadColor(x, y);
239 default:
240 UNREACHABLE();
241 }
242 return GLColor(0, 0, 0, 0);
Martin Radev8f276e22017-05-30 12:05:52 +0300243 }
244
Martin Radev3c25ad02017-08-22 17:36:53 +0300245 int mViewWidth;
246 int mViewHeight;
247 int mNumViews;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300248
Olli Etuaho44ae8992018-08-20 15:37:09 +0300249 GLuint mColorTexture;
250 GLuint mDepthTexture;
251
Olli Etuaho4836acc2018-08-20 15:23:18 +0300252 private:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300253 GLuint mDrawFramebuffer;
254 std::vector<GLuint> mReadFramebuffer;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300255 GLenum mMultiviewLayout;
Olli Etuaho44ae8992018-08-20 15:37:09 +0300256
257 void freeFBOs()
258 {
259 if (mDrawFramebuffer)
260 {
261 glDeleteFramebuffers(1, &mDrawFramebuffer);
262 mDrawFramebuffer = 0;
263 }
264 if (!mReadFramebuffer.empty())
265 {
266 glDeleteFramebuffers(mReadFramebuffer.size(), mReadFramebuffer.data());
267 mReadFramebuffer.clear();
268 }
269 if (mDepthTexture)
270 {
271 glDeleteTextures(1, &mDepthTexture);
272 mDepthTexture = 0;
273 }
274 if (mColorTexture)
275 {
276 glDeleteTextures(1, &mColorTexture);
277 mColorTexture = 0;
278 }
279 }
Martin Radev8f276e22017-05-30 12:05:52 +0300280};
281
Olli Etuaho4836acc2018-08-20 15:23:18 +0300282class MultiviewRenderTest : public MultiviewFramebufferTestBase,
Olli Etuahof26b27e2018-08-17 11:01:19 +0300283 public ::testing::TestWithParam<MultiviewRenderTestParams>
Martin Radev8f276e22017-05-30 12:05:52 +0300284{
285 protected:
Olli Etuaho4836acc2018-08-20 15:23:18 +0300286 MultiviewRenderTest() : MultiviewFramebufferTestBase(GetParam(), GetParam().mMultiviewLayout) {}
287 void SetUp() override { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300288 void TearDown() override { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
Martin Radevc1d4e552017-08-21 12:01:10 +0300289
290 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
291 {
292 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
293 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300294};
295
Jamie Madill04c084d2018-08-08 15:49:28 -0400296constexpr char kDualViewVSSource[] = R"(#version 300 es
297#extension GL_OVR_multiview : require
298layout(num_views = 2) in;
299in vec4 vPosition;
300void main()
301{
302 gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x*0.5 + 0.5 : vPosition.x*0.5);
303 gl_Position.yzw = vPosition.yzw;
304})";
305
306constexpr char kDualViewFSSource[] = R"(#version 300 es
307#extension GL_OVR_multiview : require
308precision mediump float;
309out vec4 col;
310void main()
311{
312 col = vec4(0,1,0,1);
313})";
314
Martin Radev3c25ad02017-08-22 17:36:53 +0300315class MultiviewRenderDualViewTest : public MultiviewRenderTest
316{
317 protected:
318 MultiviewRenderDualViewTest() : mProgram(0u) {}
Martin Radev8f276e22017-05-30 12:05:52 +0300319
320 void SetUp() override
321 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300322 MultiviewRenderTest::SetUp();
Martin Radev8f276e22017-05-30 12:05:52 +0300323
324 if (!requestMultiviewExtension())
325 {
326 return;
327 }
328
Olli Etuaho4836acc2018-08-20 15:23:18 +0300329 updateFBOs(2, 1, 2);
Jamie Madill04c084d2018-08-08 15:49:28 -0400330 mProgram = CompileProgram(kDualViewVSSource, kDualViewFSSource);
Martin Radev61bd9992017-08-11 13:10:55 +0300331 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300332 glUseProgram(mProgram);
333 ASSERT_GL_NO_ERROR();
334 }
335
Olli Etuaho44ae8992018-08-20 15:37:09 +0300336 void TearDown() override
337 {
338 if (mProgram != 0u)
339 {
340 glDeleteProgram(mProgram);
341 mProgram = 0u;
342 }
343
344 MultiviewRenderTest::TearDown();
345 }
346
Martin Radev8f276e22017-05-30 12:05:52 +0300347 void checkOutput()
348 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300349 EXPECT_EQ(GLColor::black, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +0300350 EXPECT_EQ(GLColor::green, GetViewColor(1, 0, 0));
351 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +0300352 EXPECT_EQ(GLColor::black, GetViewColor(1, 0, 1));
Martin Radev8f276e22017-05-30 12:05:52 +0300353 }
354
355 GLuint mProgram;
356};
357
Olli Etuaho44ae8992018-08-20 15:37:09 +0300358// Base class for tests that care mostly about draw call validity and not rendering results.
359class MultiviewDrawValidationTest : public MultiviewTest
Jamie Madill04c084d2018-08-08 15:49:28 -0400360{
361 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300362 MultiviewDrawValidationTest() : MultiviewTest() {}
Jamie Madill04c084d2018-08-08 15:49:28 -0400363
Olli Etuaho44ae8992018-08-20 15:37:09 +0300364 void initOnePixelColorTexture2D(GLuint texId)
Jamie Madill04c084d2018-08-08 15:49:28 -0400365 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300366 glBindTexture(GL_TEXTURE_2D, texId);
Jamie Madill04c084d2018-08-08 15:49:28 -0400367 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300368 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400369
Olli Etuaho44ae8992018-08-20 15:37:09 +0300370 // This initializes a simple VAO with a valid vertex buffer and index buffer with three
371 // vertices.
372 void initVAO(GLuint vao, GLuint vertexBuffer, GLuint indexBuffer)
373 {
374 glBindVertexArray(vao);
Jamie Madill04c084d2018-08-08 15:49:28 -0400375
376 const float kVertexData[3] = {0.0f};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300377 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400378 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
379
380 const unsigned int kIndices[3] = {0u, 1u, 2u};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300381 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400382 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
383 GL_STATIC_DRAW);
384 ASSERT_GL_NO_ERROR();
385 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400386};
387
Martin Radev3c25ad02017-08-22 17:36:53 +0300388class MultiviewOcclusionQueryTest : public MultiviewRenderTest
Martin Radev0d671c92017-08-10 16:41:52 +0300389{
390 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300391 MultiviewOcclusionQueryTest() {}
Martin Radev0d671c92017-08-10 16:41:52 +0300392
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400393 bool requestOcclusionQueryExtension()
394 {
395 if (extensionRequestable("GL_EXT_occlusion_query_boolean"))
396 {
397 glRequestExtensionANGLE("GL_EXT_occlusion_query_boolean");
398 }
399
400 if (!extensionEnabled("GL_EXT_occlusion_query_boolean"))
401 {
402 std::cout << "Test skipped due to missing GL_EXT_occlusion_query_boolean." << std::endl;
403 return false;
404 }
405 return true;
406 }
407
Martin Radev0d671c92017-08-10 16:41:52 +0300408 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
409 {
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400410 GLQueryEXT query;
411 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED, query);
Martin Radev0d671c92017-08-10 16:41:52 +0300412 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
413 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
414
415 GLuint result = GL_TRUE;
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400416 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT, &result);
Martin Radev0d671c92017-08-10 16:41:52 +0300417 return result;
418 }
419};
420
Olli Etuaho4bcaf992018-08-17 17:18:28 +0300421class MultiviewProgramGenerationTest : public MultiviewTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300422{
423 protected:
424 MultiviewProgramGenerationTest() {}
425};
426
Martin Radev3c25ad02017-08-22 17:36:53 +0300427class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300428{
429 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300430 MultiviewRenderPrimitiveTest() : mVBO(0u) {}
431
432 void SetUp() override
433 {
434 MultiviewRenderTest::SetUp();
435 glGenBuffers(1, &mVBO);
436 }
437
438 void TearDown() override
439 {
440 if (mVBO)
441 {
442 glDeleteBuffers(1, &mVBO);
443 mVBO = 0u;
444 }
445 MultiviewRenderTest::TearDown();
446 }
Martin Radev61bd9992017-08-11 13:10:55 +0300447
448 void setupGeometry(const std::vector<Vector2> &vertexData)
449 {
Martin Radev61bd9992017-08-11 13:10:55 +0300450 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
451 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
452 GL_STATIC_DRAW);
453 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500454 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +0300455 }
456
Martin Radev67a8a012017-09-08 13:03:52 +0300457 void checkGreenChannel(const GLubyte expectedGreenChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300458 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300459 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300460 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300461 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300462 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300463 for (int h = 0; h < mViewHeight; ++h)
464 {
465 size_t flatIndex =
466 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
Martin Radev67a8a012017-09-08 13:03:52 +0300467 EXPECT_EQ(GLColor(0, expectedGreenChannelData[flatIndex], 0, 255),
Martin Radev3c25ad02017-08-22 17:36:53 +0300468 GetViewColor(w, h, view));
469 }
Martin Radev61bd9992017-08-11 13:10:55 +0300470 }
471 }
472 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300473 GLuint mVBO;
Martin Radev61bd9992017-08-11 13:10:55 +0300474};
475
Olli Etuaho4836acc2018-08-20 15:23:18 +0300476class MultiviewSideBySideRenderTest : public MultiviewFramebufferTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300477 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev3c25ad02017-08-22 17:36:53 +0300478{
479 protected:
480 MultiviewSideBySideRenderTest()
Olli Etuaho4836acc2018-08-20 15:23:18 +0300481 : MultiviewFramebufferTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
Martin Radev3c25ad02017-08-22 17:36:53 +0300482 {
483 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300484
485 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
486 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
487 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
Martin Radevc1d4e552017-08-21 12:01:10 +0300488 {
489 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
490 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300491};
492
Olli Etuaho4836acc2018-08-20 15:23:18 +0300493class MultiviewLayeredRenderTest : public MultiviewFramebufferTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300494 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev72b4e1e2017-08-31 15:42:56 +0300495{
496 protected:
497 MultiviewLayeredRenderTest()
Olli Etuaho4836acc2018-08-20 15:23:18 +0300498 : MultiviewFramebufferTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE)
Martin Radev72b4e1e2017-08-31 15:42:56 +0300499 {
500 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300501 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
502 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
503 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
Martin Radevc1d4e552017-08-21 12:01:10 +0300504 {
505 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
506 }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300507};
508
Martin Radev14a26ae2017-07-24 15:56:29 +0300509// The test verifies that glDraw*Indirect:
510// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
511// than 1.
512// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +0300513TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300514{
515 if (!requestMultiviewExtension())
516 {
517 return;
518 }
519
Martin Radev14a26ae2017-07-24 15:56:29 +0300520 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +0300521
522 const std::string fsSource =
523 "#version 300 es\n"
524 "#extension GL_OVR_multiview : require\n"
525 "precision mediump float;\n"
526 "void main()\n"
527 "{}\n";
528
Olli Etuaho44ae8992018-08-20 15:37:09 +0300529 GLVertexArray vao;
530 GLBuffer vertexBuffer;
531 GLBuffer indexBuffer;
532 initVAO(vao, vertexBuffer, indexBuffer);
533
534 GLFramebuffer fbo;
535 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
536
Martin Radev14a26ae2017-07-24 15:56:29 +0300537 GLBuffer commandBuffer;
538 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
539 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
540 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
541 ASSERT_GL_NO_ERROR();
542
Olli Etuaho44ae8992018-08-20 15:37:09 +0300543 GLTexture tex2D;
544 initOnePixelColorTexture2D(tex2D);
545
Martin Radev14a26ae2017-07-24 15:56:29 +0300546 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
547 {
548 const std::string &vsSource =
549 "#version 300 es\n"
550 "#extension GL_OVR_multiview : require\n"
551 "layout(num_views = 2) in;\n"
552 "void main()\n"
553 "{}\n";
554 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
555 glUseProgram(program);
556
Olli Etuaho44ae8992018-08-20 15:37:09 +0300557 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
558 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300559
560 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
561 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
562
563 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
564 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
565 }
566
567 // Check that no errors are generated if the number of views is 1.
568 {
569 const std::string &vsSource =
570 "#version 300 es\n"
571 "#extension GL_OVR_multiview : require\n"
572 "layout(num_views = 1) in;\n"
573 "void main()\n"
574 "{}\n";
575 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
576 glUseProgram(program);
577
Olli Etuaho44ae8992018-08-20 15:37:09 +0300578 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
579 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300580
581 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
582 EXPECT_GL_NO_ERROR();
583
584 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
585 EXPECT_GL_NO_ERROR();
586 }
587}
588
Martin Radev7cf61662017-07-26 17:10:53 +0300589// The test verifies that glDraw*:
590// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
591// program differs.
592// 2) does not generate any error if the number of views is the same.
Martin Radev7cf61662017-07-26 17:10:53 +0300593TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
594{
595 if (!requestMultiviewExtension())
596 {
597 return;
598 }
599
600 const GLint viewportOffsets[4] = {0, 0, 2, 0};
601
602 const std::string &vsSource =
603 "#version 300 es\n"
604 "#extension GL_OVR_multiview : require\n"
605 "layout(num_views = 2) in;\n"
606 "void main()\n"
607 "{}\n";
608 const std::string &fsSource =
609 "#version 300 es\n"
610 "#extension GL_OVR_multiview : require\n"
611 "precision mediump float;\n"
612 "void main()\n"
613 "{}\n";
614 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
615 glUseProgram(program);
616
Olli Etuaho44ae8992018-08-20 15:37:09 +0300617 GLVertexArray vao;
618 GLBuffer vertexBuffer;
619 GLBuffer indexBuffer;
620 initVAO(vao, vertexBuffer, indexBuffer);
621
622 GLFramebuffer fbo;
623 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
624
625 GLTexture tex2D;
626 initOnePixelColorTexture2D(tex2D);
627
Martin Radev7cf61662017-07-26 17:10:53 +0300628 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
629 // number of views.
630 {
631 // The framebuffer has only 1 view.
Olli Etuaho44ae8992018-08-20 15:37:09 +0300632 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
633 1, &viewportOffsets[0]);
Martin Radev7cf61662017-07-26 17:10:53 +0300634
635 glDrawArrays(GL_TRIANGLES, 0, 3);
636 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
637
638 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
639 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
640 }
641
642 // Check that no errors are generated if the number of views in both program and draw
643 // framebuffer matches.
644 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300645 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
646 2, &viewportOffsets[0]);
Martin Radev7cf61662017-07-26 17:10:53 +0300647
648 glDrawArrays(GL_TRIANGLES, 0, 3);
649 EXPECT_GL_NO_ERROR();
650
651 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
652 EXPECT_GL_NO_ERROR();
653 }
Martin Radevda8e2572017-09-12 17:21:16 +0300654}
Martin Radev7cf61662017-07-26 17:10:53 +0300655
Martin Radevda8e2572017-09-12 17:21:16 +0300656// The test verifies that glDraw* generates an INVALID_OPERATION error if the program does not use
657// the multiview extension, but the active draw framebuffer has more than one view.
658TEST_P(MultiviewDrawValidationTest, NumViewsMismatchForNonMultiviewProgram)
659{
660 if (!requestMultiviewExtension())
Martin Radev7cf61662017-07-26 17:10:53 +0300661 {
Martin Radevda8e2572017-09-12 17:21:16 +0300662 return;
Martin Radev7cf61662017-07-26 17:10:53 +0300663 }
Martin Radevda8e2572017-09-12 17:21:16 +0300664
665 const std::string &vsSourceNoMultiview =
666 "#version 300 es\n"
667 "void main()\n"
668 "{}\n";
669 const std::string &fsSourceNoMultiview =
670 "#version 300 es\n"
671 "precision mediump float;\n"
672 "void main()\n"
673 "{}\n";
674 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
675 glUseProgram(programNoMultiview);
676
Olli Etuaho44ae8992018-08-20 15:37:09 +0300677 GLVertexArray vao;
678 GLBuffer vertexBuffer;
679 GLBuffer indexBuffer;
680 initVAO(vao, vertexBuffer, indexBuffer);
681
682 GLFramebuffer fbo;
683 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
684
685 GLTexture tex2D;
686 initOnePixelColorTexture2D(tex2D);
687
Martin Radevda8e2572017-09-12 17:21:16 +0300688 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300689 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 2,
Martin Radevda8e2572017-09-12 17:21:16 +0300690 &viewportOffsets[0]);
691
692 glDrawArrays(GL_TRIANGLES, 0, 3);
693 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
694
695 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
696 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radev7cf61662017-07-26 17:10:53 +0300697}
698
Martin Radev7e69f762017-07-27 14:54:13 +0300699// The test verifies that glDraw*:
700// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
701// greater than 1 and there is an active transform feedback object.
702// 2) does not generate any error if the number of views in the draw framebuffer is 1.
703TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
704{
705 if (!requestMultiviewExtension())
706 {
707 return;
708 }
709
710 const GLint viewportOffsets[4] = {0, 0, 2, 0};
711
712 const std::string &vsSource =
Olli Etuaho3755c482017-10-13 15:40:26 +0300713 R"(#version 300 es
714 out float tfVarying;
715 void main()
716 {
717 tfVarying = 1.0;
718 })";
Martin Radev7e69f762017-07-27 14:54:13 +0300719 const std::string &fsSource =
Olli Etuaho3755c482017-10-13 15:40:26 +0300720 R"(#version 300 es
721 precision mediump float;
722 void main()
723 {})";
Jamie Madill04c084d2018-08-08 15:49:28 -0400724
Olli Etuaho3755c482017-10-13 15:40:26 +0300725 std::vector<std::string> tfVaryings;
Jamie Madill04c084d2018-08-08 15:49:28 -0400726 tfVaryings.emplace_back("tfVarying");
727 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(singleViewProgram, vsSource, fsSource, tfVaryings,
Olli Etuaho3755c482017-10-13 15:40:26 +0300728 GL_SEPARATE_ATTRIBS);
Jamie Madill04c084d2018-08-08 15:49:28 -0400729
730 std::vector<std::string> dualViewTFVaryings;
731 dualViewTFVaryings.emplace_back("gl_Position");
732 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(dualViewProgram, kDualViewVSSource, kDualViewFSSource,
733 dualViewTFVaryings, GL_SEPARATE_ATTRIBS);
Martin Radev7e69f762017-07-27 14:54:13 +0300734
Olli Etuaho44ae8992018-08-20 15:37:09 +0300735 GLVertexArray vao;
736 GLBuffer vertexBuffer;
737 GLBuffer indexBuffer;
738 initVAO(vao, vertexBuffer, indexBuffer);
739
Martin Radev7e69f762017-07-27 14:54:13 +0300740 GLBuffer tbo;
741 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
Jamie Madill04c084d2018-08-08 15:49:28 -0400742 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 16u, nullptr, GL_STATIC_DRAW);
Martin Radev7e69f762017-07-27 14:54:13 +0300743
744 GLTransformFeedback transformFeedback;
745 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
Olli Etuaho3755c482017-10-13 15:40:26 +0300746
747 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
748
Jamie Madill04c084d2018-08-08 15:49:28 -0400749 glUseProgram(dualViewProgram);
Martin Radev7e69f762017-07-27 14:54:13 +0300750 glBeginTransformFeedback(GL_TRIANGLES);
751 ASSERT_GL_NO_ERROR();
752
Olli Etuaho44ae8992018-08-20 15:37:09 +0300753 GLFramebuffer fbo;
754 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
755
756 GLTexture tex2D;
757 initOnePixelColorTexture2D(tex2D);
758
Martin Radev7e69f762017-07-27 14:54:13 +0300759 // Check that drawArrays generates an error when there is an active transform feedback object
760 // and the number of views in the draw framebuffer is greater than 1.
761 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300762 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
763 2, &viewportOffsets[0]);
Martin Radev7e69f762017-07-27 14:54:13 +0300764 glDrawArrays(GL_TRIANGLES, 0, 3);
765 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
766 }
767
Jamie Madill04c084d2018-08-08 15:49:28 -0400768 glEndTransformFeedback();
769
770 // Ending transform feedback should allow the draw to succeed.
771 {
772 glDrawArrays(GL_TRIANGLES, 0, 3);
773 EXPECT_GL_NO_ERROR();
774 }
775
776 // A paused transform feedback should still trigger an error.
777 glBeginTransformFeedback(GL_TRIANGLES);
778 glPauseTransformFeedback();
779 ASSERT_GL_NO_ERROR();
780
781 glDrawArrays(GL_TRIANGLES, 0, 3);
782 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
783
784 // Unbind transform feedback - should succeed.
785 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
786 glDrawArrays(GL_TRIANGLES, 0, 3);
787 ASSERT_GL_NO_ERROR();
788
789 // Rebind paused transform feedback - should fail.
790 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
791 glDrawArrays(GL_TRIANGLES, 0, 3);
792 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
793
794 glResumeTransformFeedback();
795 glEndTransformFeedback();
796
797 glUseProgram(singleViewProgram);
798 glBeginTransformFeedback(GL_TRIANGLES);
799 ASSERT_GL_NO_ERROR();
800
Martin Radev7e69f762017-07-27 14:54:13 +0300801 // Check that drawArrays does not generate an error when the number of views in the draw
802 // framebuffer is 1.
803 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300804 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
805 1, &viewportOffsets[0]);
Martin Radev7e69f762017-07-27 14:54:13 +0300806 glDrawArrays(GL_TRIANGLES, 0, 3);
807 EXPECT_GL_NO_ERROR();
808 }
809
810 glEndTransformFeedback();
811}
812
Martin Radevffe754b2017-07-31 10:38:07 +0300813// The test verifies that glDraw*:
814// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
815// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
816// 2) does not generate any error if the number of views in the draw framebuffer is 1.
817TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
818{
Yunchao He9550c602018-02-13 14:47:05 +0800819 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radevffe754b2017-07-31 10:38:07 +0300820
Olli Etuaho94c91a92018-07-19 15:10:24 +0300821 if (extensionRequestable("GL_EXT_disjoint_timer_query"))
822 {
823 glRequestExtensionANGLE("GL_EXT_disjoint_timer_query");
824 }
825
Yunchao He9550c602018-02-13 14:47:05 +0800826 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_disjoint_timer_query"));
Martin Radevffe754b2017-07-31 10:38:07 +0300827
Olli Etuaho44ae8992018-08-20 15:37:09 +0300828 ANGLE_GL_PROGRAM(dualViewProgram, kDualViewVSSource, kDualViewFSSource);
829
Martin Radevffe754b2017-07-31 10:38:07 +0300830 const GLint viewportOffsets[4] = {0, 0, 2, 0};
831 const std::string &vsSource =
832 "#version 300 es\n"
833 "void main()\n"
834 "{}\n";
835 const std::string &fsSource =
836 "#version 300 es\n"
837 "precision mediump float;\n"
838 "void main()\n"
839 "{}\n";
Jamie Madill04c084d2018-08-08 15:49:28 -0400840 ANGLE_GL_PROGRAM(singleViewProgram, vsSource, fsSource);
841 glUseProgram(singleViewProgram);
Martin Radevffe754b2017-07-31 10:38:07 +0300842
Olli Etuaho44ae8992018-08-20 15:37:09 +0300843 GLVertexArray vao;
844 GLBuffer vertexBuffer;
845 GLBuffer indexBuffer;
846 initVAO(vao, vertexBuffer, indexBuffer);
847
Martin Radevffe754b2017-07-31 10:38:07 +0300848 GLuint query = 0u;
849 glGenQueriesEXT(1, &query);
850 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
851
Olli Etuaho44ae8992018-08-20 15:37:09 +0300852 GLFramebuffer fbo;
853 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
854
855 GLTexture tex2D;
856 initOnePixelColorTexture2D(tex2D);
857
Martin Radevffe754b2017-07-31 10:38:07 +0300858 // Check first case.
859 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300860 glUseProgram(dualViewProgram);
861 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
862 2, &viewportOffsets[0]);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300863 glClear(GL_COLOR_BUFFER_BIT);
864 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radevffe754b2017-07-31 10:38:07 +0300865 glDrawArrays(GL_TRIANGLES, 0, 3);
866 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
867 }
868
869 // Check second case.
870 {
Jamie Madill04c084d2018-08-08 15:49:28 -0400871 glUseProgram(singleViewProgram);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300872 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
873 1, &viewportOffsets[0]);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300874 glClear(GL_COLOR_BUFFER_BIT);
875 EXPECT_GL_NO_ERROR();
Martin Radevffe754b2017-07-31 10:38:07 +0300876 glDrawArrays(GL_TRIANGLES, 0, 3);
877 EXPECT_GL_NO_ERROR();
878 }
879
880 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
881 glDeleteQueries(1, &query);
Jamie Madill04c084d2018-08-08 15:49:28 -0400882
883 // Check starting a query after a successful draw.
884 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300885 glUseProgram(dualViewProgram);
886 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
887 2, &viewportOffsets[0]);
Jamie Madill04c084d2018-08-08 15:49:28 -0400888 glClear(GL_COLOR_BUFFER_BIT);
889 EXPECT_GL_NO_ERROR();
890 glDrawArrays(GL_TRIANGLES, 0, 3);
891 EXPECT_GL_NO_ERROR();
892
893 glGenQueriesEXT(1, &query);
894 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
895
896 glDrawArrays(GL_TRIANGLES, 0, 3);
897 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
898
899 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
900 glDrawArrays(GL_TRIANGLES, 0, 3);
901 EXPECT_GL_NO_ERROR();
902
903 glDeleteQueries(1, &query);
904 }
Martin Radevffe754b2017-07-31 10:38:07 +0300905}
906
Martin Radev8f276e22017-05-30 12:05:52 +0300907// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300908TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300909{
910 if (!requestMultiviewExtension())
911 {
912 return;
913 }
914 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
915 ASSERT_GL_NO_ERROR();
916
917 checkOutput();
918}
919
920// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300921TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300922{
923 if (!requestMultiviewExtension())
924 {
925 return;
926 }
927 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
928 ASSERT_GL_NO_ERROR();
929
930 checkOutput();
931}
932
933// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300934TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300935{
936 if (!requestMultiviewExtension())
937 {
938 return;
939 }
940 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
941 ASSERT_GL_NO_ERROR();
942
943 checkOutput();
944}
945
946// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300947TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300948{
949 if (!requestMultiviewExtension())
950 {
951 return;
952 }
953
954 const std::string vsSource =
955 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300956 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300957 "layout(num_views = 4) in;\n"
958 "in vec4 vPosition;\n"
959 "void main()\n"
960 "{\n"
961 " if (gl_ViewID_OVR == 0u) {\n"
962 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
963 " } else if (gl_ViewID_OVR == 1u) {\n"
964 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
965 " } else if (gl_ViewID_OVR == 2u) {\n"
966 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
967 " } else {\n"
968 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
969 " }"
970 " gl_Position.yzw = vPosition.yzw;\n"
971 "}\n";
972
973 const std::string fsSource =
974 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300975 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300976 "precision mediump float;\n"
977 "out vec4 col;\n"
978 "void main()\n"
979 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300980 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300981 "}\n";
982
Olli Etuaho4836acc2018-08-20 15:23:18 +0300983 updateFBOs(4, 1, 4);
Martin Radev8f276e22017-05-30 12:05:52 +0300984 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +0300985
986 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
987 ASSERT_GL_NO_ERROR();
988
989 for (int i = 0; i < 4; ++i)
990 {
991 for (int j = 0; j < 4; ++j)
992 {
Martin Radev8f276e22017-05-30 12:05:52 +0300993 if (i == j)
994 {
Martin Radev67a8a012017-09-08 13:03:52 +0300995 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300996 }
997 else
998 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300999 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +03001000 }
1001 }
1002 }
1003 EXPECT_GL_NO_ERROR();
1004}
1005
1006// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +03001007TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +03001008{
1009 if (!requestMultiviewExtension())
1010 {
1011 return;
1012 }
1013
1014 const std::string vsSource =
1015 "#version 300 es\n"
1016 "#extension GL_OVR_multiview : require\n"
1017 "layout(num_views = 2) in;\n"
1018 "in vec4 vPosition;\n"
1019 "void main()\n"
1020 "{\n"
1021 " vec4 p = vPosition;\n"
1022 " if (gl_InstanceID == 1){\n"
1023 " p.y = .5*p.y + .5;\n"
1024 " } else {\n"
1025 " p.y = p.y*.5;\n"
1026 " }\n"
1027 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x*0.5 + 0.5 : p.x*0.5);\n"
1028 " gl_Position.yzw = p.yzw;\n"
1029 "}\n";
1030
1031 const std::string fsSource =
1032 "#version 300 es\n"
1033 "#extension GL_OVR_multiview : require\n"
1034 "precision mediump float;\n"
1035 "out vec4 col;\n"
1036 "void main()\n"
1037 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001038 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +03001039 "}\n";
1040
Martin Radev3c25ad02017-08-22 17:36:53 +03001041 const int kViewWidth = 2;
1042 const int kViewHeight = 2;
1043 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001044 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev8f276e22017-05-30 12:05:52 +03001045 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +03001046
Martin Radev67a8a012017-09-08 13:03:52 +03001047 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 2u);
Martin Radev8f276e22017-05-30 12:05:52 +03001048 ASSERT_GL_NO_ERROR();
1049
Martin Radev67a8a012017-09-08 13:03:52 +03001050 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
1051 {{255, 0}, {255, 0}}};
Martin Radev3c25ad02017-08-22 17:36:53 +03001052
1053 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +03001054 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001055 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +03001056 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001057 for (int x = 0; x < 2; ++x)
1058 {
Martin Radev67a8a012017-09-08 13:03:52 +03001059 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][y][x], 0, 255),
Martin Radev3c25ad02017-08-22 17:36:53 +03001060 GetViewColor(x, y, view));
1061 }
Martin Radev8f276e22017-05-30 12:05:52 +03001062 }
1063 }
1064}
1065
Martin Radev553590a2017-07-31 16:40:39 +03001066// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
1067// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
1068// offset of each quad are passed as separate attributes which are indexed based on the
1069// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
1070// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
1071// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
1072// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +03001073TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +03001074{
1075 if (!requestMultiviewExtension())
1076 {
1077 return;
1078 }
1079
Corentin Wallez02cd1522018-08-22 13:46:21 +02001080 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001081 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001082 if (IsWindows() && IsD3D11())
1083 {
1084 ignoreD3D11SDKLayersWarnings();
1085 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001086
Martin Radev553590a2017-07-31 16:40:39 +03001087 const std::string &vsSource =
1088 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001089 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001090 "layout(num_views = 2) in;\n"
1091 "in vec3 vPosition;\n"
1092 "in float offsetX;\n"
1093 "in float offsetY;\n"
1094 "void main()\n"
1095 "{\n"
1096 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001097 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001098 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
1099 " gl_Position.yzw = p.yzw;\n"
1100 "}\n";
1101
1102 const std::string &fsSource =
1103 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001104 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001105 "precision mediump float;\n"
1106 "out vec4 col;\n"
1107 "void main()\n"
1108 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001109 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001110 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +03001111
1112 const int kViewWidth = 4;
1113 const int kViewHeight = 4;
1114 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001115 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev553590a2017-07-31 16:40:39 +03001116 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev553590a2017-07-31 16:40:39 +03001117
1118 GLBuffer xOffsetVBO;
1119 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1120 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
1121 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
1122 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1123 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1124 glVertexAttribDivisor(xOffsetLoc, 3);
1125 glEnableVertexAttribArray(xOffsetLoc);
1126
1127 GLBuffer yOffsetVBO;
1128 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1129 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1130 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1131 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1132 glVertexAttribDivisor(yOffsetLoc, 1);
1133 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1134 glEnableVertexAttribArray(yOffsetLoc);
1135
Martin Radev67a8a012017-09-08 13:03:52 +03001136 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev553590a2017-07-31 16:40:39 +03001137 ASSERT_GL_NO_ERROR();
1138
Martin Radev67a8a012017-09-08 13:03:52 +03001139 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001140 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1141 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1142 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +03001143 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001144 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +03001145 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001146 for (int col = 0; col < 4; ++col)
1147 {
Martin Radev67a8a012017-09-08 13:03:52 +03001148 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0, 255),
Martin Radev3c25ad02017-08-22 17:36:53 +03001149 GetViewColor(col, row, view));
1150 }
Martin Radev553590a2017-07-31 16:40:39 +03001151 }
1152 }
1153}
1154
1155// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1156// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +03001157TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +03001158{
1159 if (!requestMultiviewExtension())
1160 {
1161 return;
1162 }
1163
Olli Etuaho4836acc2018-08-20 15:23:18 +03001164 updateFBOs(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +03001165
1166 // Create multiview program.
1167 const std::string &vs =
1168 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001169 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001170 "layout(num_views = 2) in;\n"
1171 "layout(location = 0) in vec2 vPosition;\n"
1172 "layout(location = 1) in float offsetX;\n"
1173 "void main()\n"
1174 "{\n"
1175 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1176 " p.x += offsetX;\n"
1177 " gl_Position = p;\n"
1178 "}\n";
1179
1180 const std::string &fs =
1181 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001182 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001183 "precision mediump float;\n"
1184 "out vec4 col;\n"
1185 "void main()\n"
1186 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001187 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001188 "}\n";
1189
1190 ANGLE_GL_PROGRAM(program, vs, fs);
1191
1192 const std::string &dummyVS =
1193 "#version 300 es\n"
1194 "layout(location = 0) in vec2 vPosition;\n"
1195 "layout(location = 1) in float offsetX;\n"
1196 "void main()\n"
1197 "{\n"
1198 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1199 "}\n";
1200
1201 const std::string &dummyFS =
1202 "#version 300 es\n"
1203 "precision mediump float;\n"
1204 "out vec4 col;\n"
1205 "void main()\n"
1206 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001207 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001208 "}\n";
1209
1210 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
1211
1212 GLBuffer xOffsetVBO;
1213 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1214 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1215 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1216 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1217
1218 GLBuffer vertexVBO;
1219 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1220 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1221 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1222 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1223
1224 GLVertexArray vao[2];
1225 for (size_t i = 0u; i < 2u; ++i)
1226 {
1227 glBindVertexArray(vao[i]);
1228
1229 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1230 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1231 glEnableVertexAttribArray(0);
1232
1233 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1234 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1235 glEnableVertexAttribArray(1);
1236 }
1237 ASSERT_GL_NO_ERROR();
1238
1239 glViewport(0, 0, 1, 1);
1240 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001241 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001242 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001243
1244 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1245 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1246 // bits are cleared.
1247 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001248 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1249 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001250 glBindVertexArray(vao[0]);
1251 glVertexAttribDivisor(1, 0);
1252 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1253 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001254 ASSERT_GL_NO_ERROR();
1255
1256 // Check that vertexAttribDivisor uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001257 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001258 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001259 glUseProgram(program);
1260 glVertexAttribDivisor(1, 1);
1261 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001262 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1263 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001264
1265 // Clear the buffers and propagate divisor to the driver.
1266 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1267 // dirty bits when useProgram is called.
1268 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001269 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1270 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001271 glVertexAttribDivisor(1, 1);
1272 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1273 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001274 ASSERT_GL_NO_ERROR();
1275
1276 // Check that useProgram uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001277 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001278 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001279 glUseProgram(program);
1280 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001281 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1282 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001283
1284 // We go through similar steps as before.
1285 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001286 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1287 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001288 glVertexAttribDivisor(1, 1);
1289 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1290 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001291 ASSERT_GL_NO_ERROR();
1292
1293 // Check that bindVertexArray uses the number of views to update the divisor.
1294 {
1295 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1296 // divisor for vao[1] only.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001297 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001298 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001299 glBindVertexArray(vao[1]);
1300 glUseProgram(program);
1301 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001302 glBindVertexArray(0);
1303 ASSERT_GL_NO_ERROR();
1304 }
1305 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1306 // adjusts the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001307 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001308 glBindVertexArray(vao[0]);
1309 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001310 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1311 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001312}
1313
Martin Radev0d671c92017-08-10 16:41:52 +03001314// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1315// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001316TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001317{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001318 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1319 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001320
1321 const std::string vsSource =
1322 "#version 300 es\n"
1323 "#extension GL_OVR_multiview : require\n"
1324 "layout(num_views = 2) in;\n"
1325 "in vec3 vPosition;\n"
1326 "void main()\n"
1327 "{\n"
1328 " gl_Position.x = 2.0;\n"
1329 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1330 "}\n";
1331
1332 const std::string fsSource =
1333 "#version 300 es\n"
1334 "#extension GL_OVR_multiview : require\n"
1335 "precision mediump float;\n"
1336 "out vec4 col;\n"
1337 "void main()\n"
1338 "{\n"
1339 " col = vec4(1,0,0,0);\n"
1340 "}\n";
1341 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001342 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001343
1344 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1345 ASSERT_GL_NO_ERROR();
1346 EXPECT_GL_FALSE(result);
1347}
1348
1349// Test that there are fragments passing the occlusion query if only view 0 can produce
1350// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001351TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001352{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001353 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1354 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001355
1356 const std::string vsSource =
1357 "#version 300 es\n"
1358 "#extension GL_OVR_multiview : require\n"
1359 "layout(num_views = 2) in;\n"
1360 "in vec3 vPosition;\n"
1361 "void main()\n"
1362 "{\n"
1363 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1364 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1365 "}\n";
1366
1367 const std::string fsSource =
1368 "#version 300 es\n"
1369 "#extension GL_OVR_multiview : require\n"
1370 "precision mediump float;\n"
1371 "out vec4 col;\n"
1372 "void main()\n"
1373 "{\n"
1374 " col = vec4(1,0,0,0);\n"
1375 "}\n";
1376 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001377 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001378
1379 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1380 ASSERT_GL_NO_ERROR();
1381 EXPECT_GL_TRUE(result);
1382}
1383
1384// Test that there are fragments passing the occlusion query if only view 1 can produce
1385// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001386TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001387{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001388 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1389 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001390
1391 const std::string vsSource =
1392 "#version 300 es\n"
1393 "#extension GL_OVR_multiview : require\n"
1394 "layout(num_views = 2) in;\n"
1395 "in vec3 vPosition;\n"
1396 "void main()\n"
1397 "{\n"
1398 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1399 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1400 "}\n";
1401
1402 const std::string fsSource =
1403 "#version 300 es\n"
1404 "#extension GL_OVR_multiview : require\n"
1405 "precision mediump float;\n"
1406 "out vec4 col;\n"
1407 "void main()\n"
1408 "{\n"
1409 " col = vec4(1,0,0,0);\n"
1410 "}\n";
1411 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001412 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001413
1414 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1415 ASSERT_GL_NO_ERROR();
1416 EXPECT_GL_TRUE(result);
1417}
1418
Martin Radev41ac68e2017-06-06 12:16:58 +03001419// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1420// compiles and links without an error.
1421TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1422{
1423 if (!requestMultiviewExtension())
1424 {
1425 return;
1426 }
1427
1428 const std::string vsSource =
1429 "#version 300 es\n"
1430 "#extension GL_OVR_multiview : require\n"
1431 "layout(num_views = 2) in;\n"
1432 "void main()\n"
1433 "{\n"
1434 "}\n";
1435
1436 const std::string fsSource =
1437 "#version 300 es\n"
1438 "#extension GL_OVR_multiview : require\n"
1439 "precision mediump float;\n"
1440 "void main()\n"
1441 "{\n"
1442 "}\n";
1443
1444 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1445 glUseProgram(program);
1446
1447 EXPECT_GL_NO_ERROR();
1448}
1449
1450// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1451// without an error.
1452TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1453{
1454 if (!requestMultiviewExtension())
1455 {
1456 return;
1457 }
1458
1459 const std::string vsSource =
1460 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001461 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001462 "layout(num_views = 2) in;\n"
1463 "void main()\n"
1464 "{\n"
1465 " if (gl_ViewID_OVR == 0u) {\n"
1466 " gl_Position = vec4(1,0,0,1);\n"
1467 " } else {\n"
1468 " gl_Position = vec4(-1,0,0,1);\n"
1469 " }\n"
1470 "}\n";
1471
1472 const std::string fsSource =
1473 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001474 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001475 "precision mediump float;\n"
1476 "void main()\n"
1477 "{\n"
1478 "}\n";
1479
1480 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1481 glUseProgram(program);
1482
1483 EXPECT_GL_NO_ERROR();
1484}
1485
1486// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1487// without an error.
1488TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1489{
1490 if (!requestMultiviewExtension())
1491 {
1492 return;
1493 }
1494
1495 const std::string vsSource =
1496 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001497 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001498 "layout(num_views = 2) in;\n"
1499 "void main()\n"
1500 "{\n"
1501 "}\n";
1502
1503 const std::string fsSource =
1504 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001505 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001506 "precision mediump float;\n"
1507 "out vec4 col;\n"
1508 "void main()\n"
1509 "{\n"
1510 " if (gl_ViewID_OVR == 0u) {\n"
1511 " col = vec4(1,0,0,1);\n"
1512 " } else {\n"
1513 " col = vec4(-1,0,0,1);\n"
1514 " }\n"
1515 "}\n";
1516
1517 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1518 glUseProgram(program);
1519
1520 EXPECT_GL_NO_ERROR();
1521}
1522
Martin Radev61bd9992017-08-11 13:10:55 +03001523// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001524TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001525{
1526 if (!requestMultiviewExtension())
1527 {
1528 return;
1529 }
1530
Geoff Lang25858162017-11-06 11:25:58 -05001531 // Test failing on P400 graphics card (anglebug.com/2228)
1532 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1533
Martin Radev61bd9992017-08-11 13:10:55 +03001534 const std::string vsSource =
1535 "#version 300 es\n"
1536 "#extension GL_OVR_multiview : require\n"
1537 "layout(num_views = 2) in;\n"
1538 "layout(location=0) in vec2 vPosition;\n"
1539 "void main()\n"
1540 "{\n"
1541 " gl_PointSize = 1.0;\n"
1542 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1543 "}\n";
1544
1545 const std::string fsSource =
1546 "#version 300 es\n"
1547 "#extension GL_OVR_multiview : require\n"
1548 "precision mediump float;\n"
1549 "out vec4 col;\n"
1550 "void main()\n"
1551 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001552 " col = vec4(0,1,0,1);\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001553 "}\n";
1554 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1555 glUseProgram(program);
1556
Martin Radev3c25ad02017-08-22 17:36:53 +03001557 const int kViewWidth = 4;
1558 const int kViewHeight = 2;
1559 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001560 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001561
1562 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1563 std::vector<Vector2> vertexDataInClipSpace =
1564 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1565 setupGeometry(vertexDataInClipSpace);
1566
1567 glDrawArrays(GL_POINTS, 0, 2);
1568
Martin Radev67a8a012017-09-08 13:03:52 +03001569 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001570 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001571 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001572}
1573
1574// The test checks that GL_LINES is correctly rendered.
1575// The behavior of this test is not guaranteed by the spec:
1576// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1577// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1578// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1579// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001580TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001581{
1582 if (!requestMultiviewExtension())
1583 {
1584 return;
1585 }
1586
Martin Radevced5c862017-08-17 16:05:29 +03001587 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001588 ASSERT_NE(program, 0u);
1589 glUseProgram(program);
1590 ASSERT_GL_NO_ERROR();
1591
Martin Radev3c25ad02017-08-22 17:36:53 +03001592 const int kViewWidth = 4;
1593 const int kViewHeight = 2;
1594 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001595 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001596
1597 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1598 std::vector<Vector2> vertexDataInClipSpace =
1599 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1600 setupGeometry(vertexDataInClipSpace);
1601
1602 glDrawArrays(GL_LINES, 0, 2);
1603
Martin Radev67a8a012017-09-08 13:03:52 +03001604 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001605 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001606 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001607
1608 glDeleteProgram(program);
1609}
1610
1611// The test checks that GL_LINE_STRIP is correctly rendered.
1612// The behavior of this test is not guaranteed by the spec:
1613// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1614// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1615// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1616// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001617TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001618{
1619 if (!requestMultiviewExtension())
1620 {
1621 return;
1622 }
1623
Martin Radevced5c862017-08-17 16:05:29 +03001624 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001625 ASSERT_NE(program, 0u);
1626 glUseProgram(program);
1627 ASSERT_GL_NO_ERROR();
1628
Martin Radev3c25ad02017-08-22 17:36:53 +03001629 const int kViewWidth = 4;
1630 const int kViewHeight = 2;
1631 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001632 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001633
1634 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1635 std::vector<Vector2> vertexDataInClipSpace =
1636 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1637 setupGeometry(vertexDataInClipSpace);
1638
1639 glDrawArrays(GL_LINE_STRIP, 0, 3);
1640
Martin Radev67a8a012017-09-08 13:03:52 +03001641 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001642 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001643 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001644
1645 glDeleteProgram(program);
1646}
1647
1648// The test checks that GL_LINE_LOOP is correctly rendered.
1649// The behavior of this test is not guaranteed by the spec:
1650// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1651// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1652// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1653// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001654TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001655{
1656 if (!requestMultiviewExtension())
1657 {
1658 return;
1659 }
1660
Martin Radevced5c862017-08-17 16:05:29 +03001661 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001662 ASSERT_NE(program, 0u);
1663 glUseProgram(program);
1664 ASSERT_GL_NO_ERROR();
1665
Martin Radev3c25ad02017-08-22 17:36:53 +03001666 const int kViewWidth = 4;
1667 const int kViewHeight = 4;
1668 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001669 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001670
1671 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1672 Vector2I(0, 3)};
1673 std::vector<Vector2> vertexDataInClipSpace =
1674 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1675 setupGeometry(vertexDataInClipSpace);
1676
1677 glDrawArrays(GL_LINE_LOOP, 0, 4);
1678
Martin Radev67a8a012017-09-08 13:03:52 +03001679 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001680 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1681 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001682 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001683
1684 glDeleteProgram(program);
1685}
1686
1687// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001688TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001689{
1690 if (!requestMultiviewExtension())
1691 {
1692 return;
1693 }
1694
Martin Radevced5c862017-08-17 16:05:29 +03001695 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001696 ASSERT_NE(program, 0u);
1697 glUseProgram(program);
1698 ASSERT_GL_NO_ERROR();
1699
1700 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1701 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1702 setupGeometry(vertexDataInClipSpace);
1703
Martin Radev3c25ad02017-08-22 17:36:53 +03001704 const int kViewWidth = 2;
1705 const int kViewHeight = 2;
1706 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001707 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001708
1709 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1710
Martin Radev67a8a012017-09-08 13:03:52 +03001711 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1712 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1713 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001714
1715 glDeleteProgram(program);
1716}
1717
1718// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001719TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001720{
1721 if (!requestMultiviewExtension())
1722 {
1723 return;
1724 }
1725
Martin Radevced5c862017-08-17 16:05:29 +03001726 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001727 ASSERT_NE(program, 0u);
1728 glUseProgram(program);
1729 ASSERT_GL_NO_ERROR();
1730
1731 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1732 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1733 setupGeometry(vertexDataInClipSpace);
1734
Martin Radev3c25ad02017-08-22 17:36:53 +03001735 const int kViewWidth = 2;
1736 const int kViewHeight = 2;
1737 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001738 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001739
1740 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1741
Martin Radev67a8a012017-09-08 13:03:52 +03001742 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1743 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1744 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001745
1746 glDeleteProgram(program);
1747}
1748
1749// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1750// bounds. The test does not rely on the actual line width being greater than 1.0.
Martin Radev3c25ad02017-08-22 17:36:53 +03001751TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
Martin Radev61bd9992017-08-11 13:10:55 +03001752{
Luc Ferronaf7dc012018-06-26 07:56:49 -04001753 // TODO(oetuaho): Diagnose and fix http://anglebug.com/2687
1754 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11());
1755
Martin Radev61bd9992017-08-11 13:10:55 +03001756 if (!requestMultiviewExtension())
1757 {
1758 return;
1759 }
1760
Olli Etuaho4836acc2018-08-20 15:23:18 +03001761 updateFBOs(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +03001762
1763 GLint viewportOffsets[4] = {1, 0, 3, 0};
1764 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1765 mColorTexture, 0, 2, &viewportOffsets[0]);
1766 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
1767 mDepthTexture, 0, 2, &viewportOffsets[0]);
1768
1769 glViewport(0, 0, 1, 1);
1770 glScissor(0, 0, 1, 1);
1771 glEnable(GL_SCISSOR_TEST);
1772
1773 const std::string vsSource =
1774 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001775 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001776 "layout(num_views = 2) in;\n"
1777 "layout(location=0) in vec2 vPosition;\n"
1778 "void main()\n"
1779 "{\n"
1780 " gl_PointSize = 10.0;\n"
1781 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1782 "}\n";
1783
1784 const std::string fsSource =
1785 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001786 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001787 "precision mediump float;\n"
1788 "out vec4 col;\n"
1789 "void main()\n"
1790 "{\n"
1791 " if (gl_ViewID_OVR == 0u) {\n"
1792 " col = vec4(1,0,0,1);\n"
1793 " } else {\n"
1794 " col = vec4(0,1,0,1);\n"
1795 " }\n"
1796 "}\n";
1797 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1798 glUseProgram(program);
1799
1800 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1801 const std::vector<Vector2> &vertexDataInClipSpace =
1802 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001803
1804 GLBuffer vbo;
1805 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1806 glBufferData(GL_ARRAY_BUFFER, vertexDataInClipSpace.size() * sizeof(Vector2),
1807 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1808 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -05001809 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +03001810
1811 // Test rendering points.
1812 {
1813 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1814 glDrawArrays(GL_POINTS, 0, 2);
1815 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1816 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1817 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1818 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1819 }
1820
1821 // Test rendering lines.
1822 {
1823 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1824 glLineWidth(10.f);
1825 glDrawArrays(GL_LINES, 0, 2);
1826 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1827 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1828 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1829 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1830 }
1831}
1832
Martin Radev0abb7a22017-08-28 15:34:45 +03001833// Verify that re-linking a program adjusts the attribute divisor.
1834// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1835// to each other. The quads' position and color depend on the corresponding attribute divisors.
1836TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1837{
1838 if (!requestMultiviewExtension())
1839 {
1840 return;
1841 }
1842
Corentin Wallez02cd1522018-08-22 13:46:21 +02001843 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001844 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001845 if (IsWindows() && IsD3D11())
1846 {
1847 ignoreD3D11SDKLayersWarnings();
1848 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001849
Martin Radev0abb7a22017-08-28 15:34:45 +03001850 const int kViewWidth = 4;
1851 const int kViewHeight = 1;
1852 const int kNumViews = 2;
1853
1854 const std::string &fsSource =
1855 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001856 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001857 "precision mediump float;\n"
1858 "in vec4 oColor;\n"
1859 "out vec4 col;\n"
1860 "void main()\n"
1861 "{\n"
1862 " col = oColor;\n"
1863 "}\n";
1864
1865 auto generateVertexShaderSource = [](int numViews) -> std::string {
1866 std::string source =
1867 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001868 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001869 "layout(num_views = " +
1870 ToString(numViews) +
1871 ") in;\n"
1872 "in vec3 vPosition;\n"
1873 "in float vOffsetX;\n"
1874 "in vec4 vColor;\n"
1875 "out vec4 oColor;\n"
1876 "void main()\n"
1877 "{\n"
1878 " vec4 p = vec4(vPosition, 1.);\n"
1879 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1880 " oColor = vColor;\n"
1881 " gl_Position = p;\n"
1882 "}\n";
1883 return source;
1884 };
1885
1886 std::string vsSource = generateVertexShaderSource(kNumViews);
1887 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1888 glUseProgram(program);
1889
1890 GLint positionLoc;
1891 GLBuffer xOffsetVBO;
1892 GLint xOffsetLoc;
1893 GLBuffer colorVBO;
1894 GLint colorLoc;
1895
1896 {
1897 // Initialize buffers and setup attributes.
1898 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1899 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1900 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1901 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1902 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1903 glVertexAttribDivisor(xOffsetLoc, 1);
1904 glEnableVertexAttribArray(xOffsetLoc);
1905
1906 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1907 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1908 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1909 colorLoc = glGetAttribLocation(program, "vColor");
1910 glVertexAttribDivisor(colorLoc, 2);
1911 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1912 glEnableVertexAttribArray(colorLoc);
1913
1914 positionLoc = glGetAttribLocation(program, "vPosition");
1915 }
1916
1917 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001918 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001919
Martin Radev67a8a012017-09-08 13:03:52 +03001920 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001921 ASSERT_GL_NO_ERROR();
1922
1923 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1924 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1925 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1926 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1927 }
1928
1929 {
1930 const int kNewNumViews = 3;
1931 vsSource = generateVertexShaderSource(kNewNumViews);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001932 updateFBOs(kViewWidth, kViewHeight, kNewNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001933
1934 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
1935 ASSERT_NE(0u, vs);
1936 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
1937 ASSERT_NE(0u, fs);
1938
1939 GLint numAttachedShaders = 0;
1940 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1941
1942 GLuint attachedShaders[2] = {0u};
1943 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1944 for (int i = 0; i < 2; ++i)
1945 {
1946 glDetachShader(program, attachedShaders[i]);
1947 }
1948
1949 glAttachShader(program, vs);
1950 glDeleteShader(vs);
1951
1952 glAttachShader(program, fs);
1953 glDeleteShader(fs);
1954
1955 glBindAttribLocation(program, positionLoc, "vPosition");
1956 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1957 glBindAttribLocation(program, colorLoc, "vColor");
1958
1959 glLinkProgram(program);
1960
Martin Radev67a8a012017-09-08 13:03:52 +03001961 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001962 ASSERT_GL_NO_ERROR();
1963
1964 for (int i = 0; i < kNewNumViews; ++i)
1965 {
1966 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1967 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1968 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1969 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1970 }
1971 }
1972}
1973
Martin Radevced5c862017-08-17 16:05:29 +03001974// Test that useProgram applies the number of views in computing the final value of the attribute
1975// divisor.
1976TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1977{
1978 if (!requestMultiviewExtension())
1979 {
1980 return;
1981 }
1982
Geoff Lang25858162017-11-06 11:25:58 -05001983 // Test failing on P400 graphics card (anglebug.com/2228)
1984 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1985
Olli Etuaho44ae8992018-08-20 15:37:09 +03001986 // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
1987 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001988 if (IsWindows() && IsD3D11())
1989 {
1990 ignoreD3D11SDKLayersWarnings();
1991 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001992
Martin Radevced5c862017-08-17 16:05:29 +03001993 GLVertexArray vao;
1994 glBindVertexArray(vao);
1995 GLBuffer vbo;
1996 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1997 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
1998 Vector2I(3, 0)};
1999 std::vector<Vector2> vertexDataInClipSpace =
2000 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
2001 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
2002 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
2003 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
2004 glEnableVertexAttribArray(0);
2005 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
2006 glVertexAttribDivisor(0, 1);
2007 ASSERT_GL_NO_ERROR();
2008
2009 // Create a program and fbo with N views and draw N instances of a point horizontally.
2010 for (int numViews = 2; numViews <= 4; ++numViews)
2011 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03002012 updateFBOs(4, 1, numViews);
Martin Radevced5c862017-08-17 16:05:29 +03002013 ASSERT_GL_NO_ERROR();
2014
2015 GLuint program = CreateSimplePassthroughProgram(numViews);
2016 ASSERT_NE(program, 0u);
2017 glUseProgram(program);
2018 ASSERT_GL_NO_ERROR();
2019
2020 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
2021
2022 for (int view = 0; view < numViews; ++view)
2023 {
2024 for (int j = 0; j < numViews; ++j)
2025 {
Martin Radev67a8a012017-09-08 13:03:52 +03002026 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03002027 }
2028 for (int j = numViews; j < 4; ++j)
2029 {
2030 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, view));
2031 }
2032 }
2033
2034 glDeleteProgram(program);
2035 }
2036}
2037
Martin Radev72b4e1e2017-08-31 15:42:56 +03002038// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
2039TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
2040{
2041 if (!requestMultiviewExtension())
2042 {
2043 return;
2044 }
2045
2046 const std::string vsSource =
2047 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002048 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002049 "layout(num_views = 3) in;\n"
2050 "in vec3 vPosition;\n"
2051 "void main()\n"
2052 "{\n"
2053 " gl_Position = vec4(vPosition, 1.);\n"
2054 "}\n";
2055
2056 const std::string fsSource =
2057 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002058 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002059 "precision mediump float;\n"
2060 "out vec4 col;\n"
2061 "void main()\n"
2062 "{\n"
2063 " if (gl_ViewID_OVR == 0u) {\n"
2064 " col = vec4(1,0,0,1);\n"
2065 " } else if (gl_ViewID_OVR == 1u) {\n"
2066 " col = vec4(0,1,0,1);\n"
2067 " } else if (gl_ViewID_OVR == 2u) {\n"
2068 " col = vec4(0,0,1,1);\n"
2069 " } else {\n"
2070 " col = vec4(0,0,0,0);\n"
2071 " }\n"
2072 "}\n";
2073
Olli Etuaho4836acc2018-08-20 15:23:18 +03002074 updateFBOs(1, 1, 3);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002075 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002076
2077 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2078 ASSERT_GL_NO_ERROR();
2079
2080 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2081 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2082 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
2083}
2084
2085// The test checks that the inactive layers of a 2D texture array are not written to by a
2086// multi-view program.
2087TEST_P(MultiviewLayeredRenderTest, RenderToSubrageOfLayers)
2088{
2089 if (!requestMultiviewExtension())
2090 {
2091 return;
2092 }
2093
2094 const std::string vsSource =
2095 "#version 300 es\n"
2096 "#extension GL_OVR_multiview : require\n"
2097 "layout(num_views = 2) in;\n"
2098 "in vec3 vPosition;\n"
2099 "void main()\n"
2100 "{\n"
2101 " gl_Position = vec4(vPosition, 1.);\n"
2102 "}\n";
2103
2104 const std::string fsSource =
2105 "#version 300 es\n"
2106 "#extension GL_OVR_multiview : require\n"
2107 "precision mediump float;\n"
2108 "out vec4 col;\n"
2109 "void main()\n"
2110 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002111 " col = vec4(0,1,0,1);\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002112 "}\n";
2113
Olli Etuaho4836acc2018-08-20 15:23:18 +03002114 updateFBOs(1, 1, 2, 4, 1);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002115 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002116
2117 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2118 ASSERT_GL_NO_ERROR();
2119
2120 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +03002121 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2122 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002123 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
2124}
2125
Martin Radevc1d4e552017-08-21 12:01:10 +03002126// The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
2127// potential bugs if the view is selected in the VS. The test contains a program in which the
2128// gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
2129// fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
2130// never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
2131// green for view 1.
2132TEST_P(MultiviewRenderTest, FlatInterpolation)
Martin Radev3c25ad02017-08-22 17:36:53 +03002133{
Martin Radevc1d4e552017-08-21 12:01:10 +03002134 if (!requestMultiviewExtension())
2135 {
2136 return;
2137 }
2138
2139 const std::string vsSource =
2140 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002141 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002142 "layout(num_views = 2) in;\n"
2143 "in vec3 vPosition;\n"
2144 "flat out int oInstanceID;\n"
2145 "void main()\n"
2146 "{\n"
2147 " gl_Position = vec4(vPosition, 1.);\n"
2148 " oInstanceID = gl_InstanceID;\n"
2149 "}\n";
2150
2151 const std::string fsSource =
2152 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002153 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002154 "precision mediump float;\n"
2155 "flat in int oInstanceID;\n"
2156 "out vec4 col;\n"
2157 "void main()\n"
2158 "{\n"
2159 " if (oInstanceID < 0) {\n"
2160 " discard;\n"
2161 " }\n"
2162 " if (gl_ViewID_OVR == 0u) {\n"
2163 " col = vec4(1,0,0,1);\n"
2164 " } else {\n"
2165 " col = vec4(0,1,0,1);\n"
2166 " }\n"
2167 "}\n";
2168
Olli Etuaho4836acc2018-08-20 15:23:18 +03002169 updateFBOs(1, 1, 2);
Martin Radevc1d4e552017-08-21 12:01:10 +03002170 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2171
2172 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2173 ASSERT_GL_NO_ERROR();
2174
2175 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2176 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +03002177}
2178
Olli Etuaho604d8732018-07-20 11:02:43 +03002179// This test assigns gl_ViewID_OVR to a flat int varying and then sets the color based on that
2180// varying in the fragment shader.
2181TEST_P(MultiviewRenderTest, FlatInterpolation2)
2182{
2183 if (!requestMultiviewExtension())
2184 {
2185 return;
2186 }
2187
2188 const std::string vsSource =
2189 "#version 300 es\n"
2190 "#extension GL_OVR_multiview : require\n"
2191 "layout(num_views = 2) in;\n"
2192 "in vec3 vPosition;\n"
2193 "flat out int flatVarying;\n"
2194 "void main()\n"
2195 "{\n"
2196 " gl_Position = vec4(vPosition, 1.);\n"
2197 " flatVarying = int(gl_ViewID_OVR);\n"
2198 "}\n";
2199
2200 const std::string fsSource =
2201 "#version 300 es\n"
2202 "#extension GL_OVR_multiview : require\n"
2203 "precision mediump float;\n"
2204 "flat in int flatVarying;\n"
2205 "out vec4 col;\n"
2206 "void main()\n"
2207 "{\n"
2208 " if (flatVarying == 0) {\n"
2209 " col = vec4(1,0,0,1);\n"
2210 " } else {\n"
2211 " col = vec4(0,1,0,1);\n"
2212 " }\n"
2213 "}\n";
2214
Olli Etuaho4836acc2018-08-20 15:23:18 +03002215 updateFBOs(1, 1, 2);
Olli Etuaho604d8732018-07-20 11:02:43 +03002216 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2217
2218 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2219 ASSERT_GL_NO_ERROR();
2220
2221 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2222 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2223}
2224
Martin Radev265a6d42017-09-12 16:51:37 +03002225// The test is added to cover a bug which resulted in the viewport/scissor and viewport offsets not
2226// being correctly applied.
2227TEST_P(MultiviewSideBySideRenderTest, ViewportOffsetsAppliedBugCoverage)
2228{
2229 if (!requestMultiviewExtension())
2230 {
2231 return;
2232 }
2233
Olli Etuaho4836acc2018-08-20 15:23:18 +03002234 updateFBOs(1, 1, 2);
Martin Radev265a6d42017-09-12 16:51:37 +03002235
2236 // Create multiview program.
2237 const std::string &vs =
2238 "#version 300 es\n"
2239 "#extension GL_OVR_multiview : require\n"
2240 "layout(num_views = 2) in;\n"
2241 "layout(location = 0) in vec3 vPosition;\n"
2242 "void main()\n"
2243 "{\n"
2244 " gl_Position = vec4(vPosition, 1.0);\n"
2245 "}\n";
2246
2247 const std::string &fs =
2248 "#version 300 es\n"
2249 "#extension GL_OVR_multiview : require\n"
2250 "precision mediump float;\n"
2251 "out vec4 col;\n"
2252 "void main()\n"
2253 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002254 " col = vec4(0,1,0,1);\n"
Martin Radev265a6d42017-09-12 16:51:37 +03002255 "}\n";
2256
2257 ANGLE_GL_PROGRAM(program, vs, fs);
2258
2259 glViewport(0, 0, 1, 1);
2260 glScissor(0, 0, 1, 1);
2261 glEnable(GL_SCISSOR_TEST);
2262 glClearColor(0, 0, 0, 1);
2263
2264 // Bind the default FBO and make sure that the state is synchronized.
2265 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
2266 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2267 ASSERT_GL_NO_ERROR();
2268
2269 // Draw and check that both views are rendered to.
Olli Etuaho4836acc2018-08-20 15:23:18 +03002270 bindMemberDrawFramebuffer();
Martin Radev265a6d42017-09-12 16:51:37 +03002271 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev67a8a012017-09-08 13:03:52 +03002272
Martin Radev265a6d42017-09-12 16:51:37 +03002273 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
Martin Radev67a8a012017-09-08 13:03:52 +03002274 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
2275 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev265a6d42017-09-12 16:51:37 +03002276}
2277
Olli Etuahof26b27e2018-08-17 11:01:19 +03002278MultiviewRenderTestParams SideBySideVertexShaderOpenGL(GLint majorVersion = 3,
2279 GLint minorVersion = 0)
Martin Radev3c25ad02017-08-22 17:36:53 +03002280{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002281 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE,
2282 VertexShaderOpenGL(majorVersion, minorVersion));
Martin Radev3c25ad02017-08-22 17:36:53 +03002283}
2284
Olli Etuahof26b27e2018-08-17 11:01:19 +03002285MultiviewRenderTestParams LayeredVertexShaderOpenGL()
Martin Radev3c25ad02017-08-22 17:36:53 +03002286{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002287 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
2288 VertexShaderOpenGL(3, 0));
Martin Radev3c25ad02017-08-22 17:36:53 +03002289}
2290
Olli Etuahof26b27e2018-08-17 11:01:19 +03002291MultiviewRenderTestParams SideBySideGeomShaderD3D11()
Martin Radev72b4e1e2017-08-31 15:42:56 +03002292{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002293 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE,
2294 GeomShaderD3D11(3, 0));
Martin Radevc1d4e552017-08-21 12:01:10 +03002295}
2296
Olli Etuahof26b27e2018-08-17 11:01:19 +03002297MultiviewRenderTestParams LayeredGeomShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002298{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002299 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, GeomShaderD3D11(3, 0));
Martin Radevc1d4e552017-08-21 12:01:10 +03002300}
2301
Olli Etuahof26b27e2018-08-17 11:01:19 +03002302MultiviewRenderTestParams SideBySideVertexShaderD3D11(GLint majorVersion = 3,
2303 GLint minorVersion = 0)
Martin Radevc1d4e552017-08-21 12:01:10 +03002304{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002305 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE,
2306 VertexShaderD3D11(majorVersion, minorVersion));
Martin Radevc1d4e552017-08-21 12:01:10 +03002307}
2308
Olli Etuahof26b27e2018-08-17 11:01:19 +03002309MultiviewRenderTestParams LayeredVertexShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002310{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002311 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
2312 VertexShaderD3D11(3, 0));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002313}
2314
Jamie Madill04c084d2018-08-08 15:49:28 -04002315ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest,
Olli Etuaho44ae8992018-08-20 15:37:09 +03002316 VertexShaderOpenGL(3, 1),
2317 VertexShaderD3D11(3, 1));
Martin Radevced5c862017-08-17 16:05:29 +03002318ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002319 SideBySideVertexShaderOpenGL(),
2320 LayeredVertexShaderOpenGL(),
2321 SideBySideGeomShaderD3D11(),
2322 SideBySideVertexShaderD3D11(),
2323 LayeredGeomShaderD3D11(),
2324 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002325ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002326 SideBySideVertexShaderOpenGL(),
2327 LayeredVertexShaderOpenGL(),
2328 SideBySideGeomShaderD3D11(),
2329 SideBySideVertexShaderD3D11(),
2330 LayeredGeomShaderD3D11(),
2331 LayeredVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002332ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002333 SideBySideVertexShaderOpenGL(),
2334 LayeredVertexShaderOpenGL(),
2335 SideBySideGeomShaderD3D11(),
2336 SideBySideVertexShaderD3D11(),
2337 LayeredGeomShaderD3D11(),
2338 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002339ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
Olli Etuaho4bcaf992018-08-17 17:18:28 +03002340 VertexShaderOpenGL(3, 0),
2341 GeomShaderD3D11(3, 0),
2342 VertexShaderD3D11(3, 0));
Martin Radevced5c862017-08-17 16:05:29 +03002343ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002344 SideBySideVertexShaderOpenGL(),
2345 LayeredVertexShaderOpenGL(),
2346 SideBySideGeomShaderD3D11(),
2347 SideBySideVertexShaderD3D11(),
2348 LayeredGeomShaderD3D11(),
2349 LayeredVertexShaderD3D11());
Jamie Madill04c084d2018-08-08 15:49:28 -04002350ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest,
2351 VertexShaderOpenGL(3, 0),
2352 GeomShaderD3D11(3, 0));
2353ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, VertexShaderOpenGL(3, 0), GeomShaderD3D11(3, 0));