blob: c3d99ee7c5df73acca2eae72f8f5b2b373da3278 [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
Olli Etuaho44ae8992018-08-20 15:37:09 +03001080 // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
1081 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
1082 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsAMD());
1083
Martin Radev553590a2017-07-31 16:40:39 +03001084 const std::string &vsSource =
1085 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001086 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001087 "layout(num_views = 2) in;\n"
1088 "in vec3 vPosition;\n"
1089 "in float offsetX;\n"
1090 "in float offsetY;\n"
1091 "void main()\n"
1092 "{\n"
1093 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001094 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001095 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
1096 " gl_Position.yzw = p.yzw;\n"
1097 "}\n";
1098
1099 const std::string &fsSource =
1100 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001101 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001102 "precision mediump float;\n"
1103 "out vec4 col;\n"
1104 "void main()\n"
1105 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001106 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001107 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +03001108
1109 const int kViewWidth = 4;
1110 const int kViewHeight = 4;
1111 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001112 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev553590a2017-07-31 16:40:39 +03001113 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev553590a2017-07-31 16:40:39 +03001114
1115 GLBuffer xOffsetVBO;
1116 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1117 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
1118 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
1119 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1120 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1121 glVertexAttribDivisor(xOffsetLoc, 3);
1122 glEnableVertexAttribArray(xOffsetLoc);
1123
1124 GLBuffer yOffsetVBO;
1125 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1126 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1127 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1128 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1129 glVertexAttribDivisor(yOffsetLoc, 1);
1130 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1131 glEnableVertexAttribArray(yOffsetLoc);
1132
Martin Radev67a8a012017-09-08 13:03:52 +03001133 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev553590a2017-07-31 16:40:39 +03001134 ASSERT_GL_NO_ERROR();
1135
Martin Radev67a8a012017-09-08 13:03:52 +03001136 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001137 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1138 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1139 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +03001140 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001141 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +03001142 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001143 for (int col = 0; col < 4; ++col)
1144 {
Martin Radev67a8a012017-09-08 13:03:52 +03001145 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0, 255),
Martin Radev3c25ad02017-08-22 17:36:53 +03001146 GetViewColor(col, row, view));
1147 }
Martin Radev553590a2017-07-31 16:40:39 +03001148 }
1149 }
1150}
1151
1152// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1153// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +03001154TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +03001155{
1156 if (!requestMultiviewExtension())
1157 {
1158 return;
1159 }
1160
Olli Etuaho4836acc2018-08-20 15:23:18 +03001161 updateFBOs(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +03001162
1163 // Create multiview program.
1164 const std::string &vs =
1165 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001166 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001167 "layout(num_views = 2) in;\n"
1168 "layout(location = 0) in vec2 vPosition;\n"
1169 "layout(location = 1) in float offsetX;\n"
1170 "void main()\n"
1171 "{\n"
1172 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1173 " p.x += offsetX;\n"
1174 " gl_Position = p;\n"
1175 "}\n";
1176
1177 const std::string &fs =
1178 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001179 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001180 "precision mediump float;\n"
1181 "out vec4 col;\n"
1182 "void main()\n"
1183 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001184 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001185 "}\n";
1186
1187 ANGLE_GL_PROGRAM(program, vs, fs);
1188
1189 const std::string &dummyVS =
1190 "#version 300 es\n"
1191 "layout(location = 0) in vec2 vPosition;\n"
1192 "layout(location = 1) in float offsetX;\n"
1193 "void main()\n"
1194 "{\n"
1195 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1196 "}\n";
1197
1198 const std::string &dummyFS =
1199 "#version 300 es\n"
1200 "precision mediump float;\n"
1201 "out vec4 col;\n"
1202 "void main()\n"
1203 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001204 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001205 "}\n";
1206
1207 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
1208
1209 GLBuffer xOffsetVBO;
1210 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1211 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1212 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1213 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1214
1215 GLBuffer vertexVBO;
1216 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1217 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1218 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1219 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1220
1221 GLVertexArray vao[2];
1222 for (size_t i = 0u; i < 2u; ++i)
1223 {
1224 glBindVertexArray(vao[i]);
1225
1226 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1227 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1228 glEnableVertexAttribArray(0);
1229
1230 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1231 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1232 glEnableVertexAttribArray(1);
1233 }
1234 ASSERT_GL_NO_ERROR();
1235
1236 glViewport(0, 0, 1, 1);
1237 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001238 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001239 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001240
1241 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1242 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1243 // bits are cleared.
1244 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001245 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1246 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001247 glBindVertexArray(vao[0]);
1248 glVertexAttribDivisor(1, 0);
1249 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1250 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001251 ASSERT_GL_NO_ERROR();
1252
1253 // Check that vertexAttribDivisor uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001254 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001255 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001256 glUseProgram(program);
1257 glVertexAttribDivisor(1, 1);
1258 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001259 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1260 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001261
1262 // Clear the buffers and propagate divisor to the driver.
1263 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1264 // dirty bits when useProgram is called.
1265 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001266 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1267 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001268 glVertexAttribDivisor(1, 1);
1269 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1270 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001271 ASSERT_GL_NO_ERROR();
1272
1273 // Check that useProgram uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001274 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001275 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001276 glUseProgram(program);
1277 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001278 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1279 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001280
1281 // We go through similar steps as before.
1282 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001283 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1284 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001285 glVertexAttribDivisor(1, 1);
1286 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1287 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001288 ASSERT_GL_NO_ERROR();
1289
1290 // Check that bindVertexArray uses the number of views to update the divisor.
1291 {
1292 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1293 // divisor for vao[1] only.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001294 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001295 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001296 glBindVertexArray(vao[1]);
1297 glUseProgram(program);
1298 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001299 glBindVertexArray(0);
1300 ASSERT_GL_NO_ERROR();
1301 }
1302 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1303 // adjusts the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001304 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001305 glBindVertexArray(vao[0]);
1306 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001307 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1308 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001309}
1310
Martin Radev0d671c92017-08-10 16:41:52 +03001311// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1312// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001313TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001314{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001315 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1316 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001317
1318 const std::string vsSource =
1319 "#version 300 es\n"
1320 "#extension GL_OVR_multiview : require\n"
1321 "layout(num_views = 2) in;\n"
1322 "in vec3 vPosition;\n"
1323 "void main()\n"
1324 "{\n"
1325 " gl_Position.x = 2.0;\n"
1326 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1327 "}\n";
1328
1329 const std::string fsSource =
1330 "#version 300 es\n"
1331 "#extension GL_OVR_multiview : require\n"
1332 "precision mediump float;\n"
1333 "out vec4 col;\n"
1334 "void main()\n"
1335 "{\n"
1336 " col = vec4(1,0,0,0);\n"
1337 "}\n";
1338 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001339 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001340
1341 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1342 ASSERT_GL_NO_ERROR();
1343 EXPECT_GL_FALSE(result);
1344}
1345
1346// Test that there are fragments passing the occlusion query if only view 0 can produce
1347// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001348TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001349{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001350 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1351 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001352
1353 const std::string vsSource =
1354 "#version 300 es\n"
1355 "#extension GL_OVR_multiview : require\n"
1356 "layout(num_views = 2) in;\n"
1357 "in vec3 vPosition;\n"
1358 "void main()\n"
1359 "{\n"
1360 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1361 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1362 "}\n";
1363
1364 const std::string fsSource =
1365 "#version 300 es\n"
1366 "#extension GL_OVR_multiview : require\n"
1367 "precision mediump float;\n"
1368 "out vec4 col;\n"
1369 "void main()\n"
1370 "{\n"
1371 " col = vec4(1,0,0,0);\n"
1372 "}\n";
1373 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001374 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001375
1376 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1377 ASSERT_GL_NO_ERROR();
1378 EXPECT_GL_TRUE(result);
1379}
1380
1381// Test that there are fragments passing the occlusion query if only view 1 can produce
1382// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001383TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001384{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001385 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1386 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001387
1388 const std::string vsSource =
1389 "#version 300 es\n"
1390 "#extension GL_OVR_multiview : require\n"
1391 "layout(num_views = 2) in;\n"
1392 "in vec3 vPosition;\n"
1393 "void main()\n"
1394 "{\n"
1395 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1396 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1397 "}\n";
1398
1399 const std::string fsSource =
1400 "#version 300 es\n"
1401 "#extension GL_OVR_multiview : require\n"
1402 "precision mediump float;\n"
1403 "out vec4 col;\n"
1404 "void main()\n"
1405 "{\n"
1406 " col = vec4(1,0,0,0);\n"
1407 "}\n";
1408 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001409 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001410
1411 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1412 ASSERT_GL_NO_ERROR();
1413 EXPECT_GL_TRUE(result);
1414}
1415
Martin Radev41ac68e2017-06-06 12:16:58 +03001416// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1417// compiles and links without an error.
1418TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1419{
1420 if (!requestMultiviewExtension())
1421 {
1422 return;
1423 }
1424
1425 const std::string vsSource =
1426 "#version 300 es\n"
1427 "#extension GL_OVR_multiview : require\n"
1428 "layout(num_views = 2) in;\n"
1429 "void main()\n"
1430 "{\n"
1431 "}\n";
1432
1433 const std::string fsSource =
1434 "#version 300 es\n"
1435 "#extension GL_OVR_multiview : require\n"
1436 "precision mediump float;\n"
1437 "void main()\n"
1438 "{\n"
1439 "}\n";
1440
1441 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1442 glUseProgram(program);
1443
1444 EXPECT_GL_NO_ERROR();
1445}
1446
1447// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1448// without an error.
1449TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1450{
1451 if (!requestMultiviewExtension())
1452 {
1453 return;
1454 }
1455
1456 const std::string vsSource =
1457 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001458 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001459 "layout(num_views = 2) in;\n"
1460 "void main()\n"
1461 "{\n"
1462 " if (gl_ViewID_OVR == 0u) {\n"
1463 " gl_Position = vec4(1,0,0,1);\n"
1464 " } else {\n"
1465 " gl_Position = vec4(-1,0,0,1);\n"
1466 " }\n"
1467 "}\n";
1468
1469 const std::string fsSource =
1470 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001471 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001472 "precision mediump float;\n"
1473 "void main()\n"
1474 "{\n"
1475 "}\n";
1476
1477 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1478 glUseProgram(program);
1479
1480 EXPECT_GL_NO_ERROR();
1481}
1482
1483// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1484// without an error.
1485TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1486{
1487 if (!requestMultiviewExtension())
1488 {
1489 return;
1490 }
1491
1492 const std::string vsSource =
1493 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001494 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001495 "layout(num_views = 2) in;\n"
1496 "void main()\n"
1497 "{\n"
1498 "}\n";
1499
1500 const std::string fsSource =
1501 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001502 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001503 "precision mediump float;\n"
1504 "out vec4 col;\n"
1505 "void main()\n"
1506 "{\n"
1507 " if (gl_ViewID_OVR == 0u) {\n"
1508 " col = vec4(1,0,0,1);\n"
1509 " } else {\n"
1510 " col = vec4(-1,0,0,1);\n"
1511 " }\n"
1512 "}\n";
1513
1514 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1515 glUseProgram(program);
1516
1517 EXPECT_GL_NO_ERROR();
1518}
1519
Martin Radev61bd9992017-08-11 13:10:55 +03001520// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001521TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001522{
1523 if (!requestMultiviewExtension())
1524 {
1525 return;
1526 }
1527
Geoff Lang25858162017-11-06 11:25:58 -05001528 // Test failing on P400 graphics card (anglebug.com/2228)
1529 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1530
Martin Radev61bd9992017-08-11 13:10:55 +03001531 const std::string vsSource =
1532 "#version 300 es\n"
1533 "#extension GL_OVR_multiview : require\n"
1534 "layout(num_views = 2) in;\n"
1535 "layout(location=0) in vec2 vPosition;\n"
1536 "void main()\n"
1537 "{\n"
1538 " gl_PointSize = 1.0;\n"
1539 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1540 "}\n";
1541
1542 const std::string fsSource =
1543 "#version 300 es\n"
1544 "#extension GL_OVR_multiview : require\n"
1545 "precision mediump float;\n"
1546 "out vec4 col;\n"
1547 "void main()\n"
1548 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001549 " col = vec4(0,1,0,1);\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001550 "}\n";
1551 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1552 glUseProgram(program);
1553
Martin Radev3c25ad02017-08-22 17:36:53 +03001554 const int kViewWidth = 4;
1555 const int kViewHeight = 2;
1556 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001557 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001558
1559 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1560 std::vector<Vector2> vertexDataInClipSpace =
1561 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1562 setupGeometry(vertexDataInClipSpace);
1563
1564 glDrawArrays(GL_POINTS, 0, 2);
1565
Martin Radev67a8a012017-09-08 13:03:52 +03001566 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001567 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001568 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001569}
1570
1571// The test checks that GL_LINES is correctly rendered.
1572// The behavior of this test is not guaranteed by the spec:
1573// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1574// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1575// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1576// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001577TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001578{
1579 if (!requestMultiviewExtension())
1580 {
1581 return;
1582 }
1583
Martin Radevced5c862017-08-17 16:05:29 +03001584 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001585 ASSERT_NE(program, 0u);
1586 glUseProgram(program);
1587 ASSERT_GL_NO_ERROR();
1588
Martin Radev3c25ad02017-08-22 17:36:53 +03001589 const int kViewWidth = 4;
1590 const int kViewHeight = 2;
1591 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001592 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001593
1594 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1595 std::vector<Vector2> vertexDataInClipSpace =
1596 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1597 setupGeometry(vertexDataInClipSpace);
1598
1599 glDrawArrays(GL_LINES, 0, 2);
1600
Martin Radev67a8a012017-09-08 13:03:52 +03001601 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001602 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001603 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001604
1605 glDeleteProgram(program);
1606}
1607
1608// The test checks that GL_LINE_STRIP is correctly rendered.
1609// The behavior of this test is not guaranteed by the spec:
1610// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1611// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1612// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1613// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001614TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001615{
1616 if (!requestMultiviewExtension())
1617 {
1618 return;
1619 }
1620
Martin Radevced5c862017-08-17 16:05:29 +03001621 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001622 ASSERT_NE(program, 0u);
1623 glUseProgram(program);
1624 ASSERT_GL_NO_ERROR();
1625
Martin Radev3c25ad02017-08-22 17:36:53 +03001626 const int kViewWidth = 4;
1627 const int kViewHeight = 2;
1628 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001629 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001630
1631 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1632 std::vector<Vector2> vertexDataInClipSpace =
1633 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1634 setupGeometry(vertexDataInClipSpace);
1635
1636 glDrawArrays(GL_LINE_STRIP, 0, 3);
1637
Martin Radev67a8a012017-09-08 13:03:52 +03001638 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001639 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001640 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001641
1642 glDeleteProgram(program);
1643}
1644
1645// The test checks that GL_LINE_LOOP is correctly rendered.
1646// The behavior of this test is not guaranteed by the spec:
1647// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1648// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1649// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1650// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001651TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001652{
1653 if (!requestMultiviewExtension())
1654 {
1655 return;
1656 }
1657
Martin Radevced5c862017-08-17 16:05:29 +03001658 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001659 ASSERT_NE(program, 0u);
1660 glUseProgram(program);
1661 ASSERT_GL_NO_ERROR();
1662
Martin Radev3c25ad02017-08-22 17:36:53 +03001663 const int kViewWidth = 4;
1664 const int kViewHeight = 4;
1665 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001666 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001667
1668 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1669 Vector2I(0, 3)};
1670 std::vector<Vector2> vertexDataInClipSpace =
1671 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1672 setupGeometry(vertexDataInClipSpace);
1673
1674 glDrawArrays(GL_LINE_LOOP, 0, 4);
1675
Martin Radev67a8a012017-09-08 13:03:52 +03001676 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001677 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1678 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001679 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001680
1681 glDeleteProgram(program);
1682}
1683
1684// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001685TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001686{
1687 if (!requestMultiviewExtension())
1688 {
1689 return;
1690 }
1691
Martin Radevced5c862017-08-17 16:05:29 +03001692 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001693 ASSERT_NE(program, 0u);
1694 glUseProgram(program);
1695 ASSERT_GL_NO_ERROR();
1696
1697 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1698 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1699 setupGeometry(vertexDataInClipSpace);
1700
Martin Radev3c25ad02017-08-22 17:36:53 +03001701 const int kViewWidth = 2;
1702 const int kViewHeight = 2;
1703 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001704 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001705
1706 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1707
Martin Radev67a8a012017-09-08 13:03:52 +03001708 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1709 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1710 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001711
1712 glDeleteProgram(program);
1713}
1714
1715// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001716TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001717{
1718 if (!requestMultiviewExtension())
1719 {
1720 return;
1721 }
1722
Martin Radevced5c862017-08-17 16:05:29 +03001723 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001724 ASSERT_NE(program, 0u);
1725 glUseProgram(program);
1726 ASSERT_GL_NO_ERROR();
1727
1728 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1729 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1730 setupGeometry(vertexDataInClipSpace);
1731
Martin Radev3c25ad02017-08-22 17:36:53 +03001732 const int kViewWidth = 2;
1733 const int kViewHeight = 2;
1734 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001735 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001736
1737 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1738
Martin Radev67a8a012017-09-08 13:03:52 +03001739 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1740 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1741 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001742
1743 glDeleteProgram(program);
1744}
1745
1746// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1747// bounds. The test does not rely on the actual line width being greater than 1.0.
Martin Radev3c25ad02017-08-22 17:36:53 +03001748TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
Martin Radev61bd9992017-08-11 13:10:55 +03001749{
Luc Ferronaf7dc012018-06-26 07:56:49 -04001750 // TODO(oetuaho): Diagnose and fix http://anglebug.com/2687
1751 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11());
1752
Martin Radev61bd9992017-08-11 13:10:55 +03001753 if (!requestMultiviewExtension())
1754 {
1755 return;
1756 }
1757
Olli Etuaho4836acc2018-08-20 15:23:18 +03001758 updateFBOs(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +03001759
1760 GLint viewportOffsets[4] = {1, 0, 3, 0};
1761 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1762 mColorTexture, 0, 2, &viewportOffsets[0]);
1763 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
1764 mDepthTexture, 0, 2, &viewportOffsets[0]);
1765
1766 glViewport(0, 0, 1, 1);
1767 glScissor(0, 0, 1, 1);
1768 glEnable(GL_SCISSOR_TEST);
1769
1770 const std::string vsSource =
1771 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001772 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001773 "layout(num_views = 2) in;\n"
1774 "layout(location=0) in vec2 vPosition;\n"
1775 "void main()\n"
1776 "{\n"
1777 " gl_PointSize = 10.0;\n"
1778 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1779 "}\n";
1780
1781 const std::string fsSource =
1782 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001783 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001784 "precision mediump float;\n"
1785 "out vec4 col;\n"
1786 "void main()\n"
1787 "{\n"
1788 " if (gl_ViewID_OVR == 0u) {\n"
1789 " col = vec4(1,0,0,1);\n"
1790 " } else {\n"
1791 " col = vec4(0,1,0,1);\n"
1792 " }\n"
1793 "}\n";
1794 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1795 glUseProgram(program);
1796
1797 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1798 const std::vector<Vector2> &vertexDataInClipSpace =
1799 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001800
1801 GLBuffer vbo;
1802 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1803 glBufferData(GL_ARRAY_BUFFER, vertexDataInClipSpace.size() * sizeof(Vector2),
1804 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1805 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -05001806 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +03001807
1808 // Test rendering points.
1809 {
1810 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1811 glDrawArrays(GL_POINTS, 0, 2);
1812 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1813 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1814 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1815 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1816 }
1817
1818 // Test rendering lines.
1819 {
1820 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1821 glLineWidth(10.f);
1822 glDrawArrays(GL_LINES, 0, 2);
1823 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1824 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1825 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1826 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1827 }
1828}
1829
Martin Radev0abb7a22017-08-28 15:34:45 +03001830// Verify that re-linking a program adjusts the attribute divisor.
1831// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1832// to each other. The quads' position and color depend on the corresponding attribute divisors.
1833TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1834{
1835 if (!requestMultiviewExtension())
1836 {
1837 return;
1838 }
1839
Olli Etuaho44ae8992018-08-20 15:37:09 +03001840 // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
1841 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
1842 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsAMD());
1843
Martin Radev0abb7a22017-08-28 15:34:45 +03001844 const int kViewWidth = 4;
1845 const int kViewHeight = 1;
1846 const int kNumViews = 2;
1847
1848 const std::string &fsSource =
1849 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001850 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001851 "precision mediump float;\n"
1852 "in vec4 oColor;\n"
1853 "out vec4 col;\n"
1854 "void main()\n"
1855 "{\n"
1856 " col = oColor;\n"
1857 "}\n";
1858
1859 auto generateVertexShaderSource = [](int numViews) -> std::string {
1860 std::string source =
1861 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001862 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001863 "layout(num_views = " +
1864 ToString(numViews) +
1865 ") in;\n"
1866 "in vec3 vPosition;\n"
1867 "in float vOffsetX;\n"
1868 "in vec4 vColor;\n"
1869 "out vec4 oColor;\n"
1870 "void main()\n"
1871 "{\n"
1872 " vec4 p = vec4(vPosition, 1.);\n"
1873 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1874 " oColor = vColor;\n"
1875 " gl_Position = p;\n"
1876 "}\n";
1877 return source;
1878 };
1879
1880 std::string vsSource = generateVertexShaderSource(kNumViews);
1881 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1882 glUseProgram(program);
1883
1884 GLint positionLoc;
1885 GLBuffer xOffsetVBO;
1886 GLint xOffsetLoc;
1887 GLBuffer colorVBO;
1888 GLint colorLoc;
1889
1890 {
1891 // Initialize buffers and setup attributes.
1892 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1893 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1894 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1895 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1896 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1897 glVertexAttribDivisor(xOffsetLoc, 1);
1898 glEnableVertexAttribArray(xOffsetLoc);
1899
1900 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1901 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1902 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1903 colorLoc = glGetAttribLocation(program, "vColor");
1904 glVertexAttribDivisor(colorLoc, 2);
1905 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1906 glEnableVertexAttribArray(colorLoc);
1907
1908 positionLoc = glGetAttribLocation(program, "vPosition");
1909 }
1910
1911 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001912 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001913
Martin Radev67a8a012017-09-08 13:03:52 +03001914 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001915 ASSERT_GL_NO_ERROR();
1916
1917 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1918 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1919 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1920 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1921 }
1922
1923 {
1924 const int kNewNumViews = 3;
1925 vsSource = generateVertexShaderSource(kNewNumViews);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001926 updateFBOs(kViewWidth, kViewHeight, kNewNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001927
1928 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
1929 ASSERT_NE(0u, vs);
1930 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
1931 ASSERT_NE(0u, fs);
1932
1933 GLint numAttachedShaders = 0;
1934 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1935
1936 GLuint attachedShaders[2] = {0u};
1937 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1938 for (int i = 0; i < 2; ++i)
1939 {
1940 glDetachShader(program, attachedShaders[i]);
1941 }
1942
1943 glAttachShader(program, vs);
1944 glDeleteShader(vs);
1945
1946 glAttachShader(program, fs);
1947 glDeleteShader(fs);
1948
1949 glBindAttribLocation(program, positionLoc, "vPosition");
1950 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1951 glBindAttribLocation(program, colorLoc, "vColor");
1952
1953 glLinkProgram(program);
1954
Martin Radev67a8a012017-09-08 13:03:52 +03001955 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001956 ASSERT_GL_NO_ERROR();
1957
1958 for (int i = 0; i < kNewNumViews; ++i)
1959 {
1960 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1961 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1962 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1963 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1964 }
1965 }
1966}
1967
Martin Radevced5c862017-08-17 16:05:29 +03001968// Test that useProgram applies the number of views in computing the final value of the attribute
1969// divisor.
1970TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1971{
1972 if (!requestMultiviewExtension())
1973 {
1974 return;
1975 }
1976
Geoff Lang25858162017-11-06 11:25:58 -05001977 // Test failing on P400 graphics card (anglebug.com/2228)
1978 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1979
Olli Etuaho44ae8992018-08-20 15:37:09 +03001980 // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
1981 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
1982 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsAMD());
1983
Martin Radevced5c862017-08-17 16:05:29 +03001984 GLVertexArray vao;
1985 glBindVertexArray(vao);
1986 GLBuffer vbo;
1987 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1988 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
1989 Vector2I(3, 0)};
1990 std::vector<Vector2> vertexDataInClipSpace =
1991 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
1992 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
1993 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
1994 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1995 glEnableVertexAttribArray(0);
1996 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
1997 glVertexAttribDivisor(0, 1);
1998 ASSERT_GL_NO_ERROR();
1999
2000 // Create a program and fbo with N views and draw N instances of a point horizontally.
2001 for (int numViews = 2; numViews <= 4; ++numViews)
2002 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03002003 updateFBOs(4, 1, numViews);
Martin Radevced5c862017-08-17 16:05:29 +03002004 ASSERT_GL_NO_ERROR();
2005
2006 GLuint program = CreateSimplePassthroughProgram(numViews);
2007 ASSERT_NE(program, 0u);
2008 glUseProgram(program);
2009 ASSERT_GL_NO_ERROR();
2010
2011 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
2012
2013 for (int view = 0; view < numViews; ++view)
2014 {
2015 for (int j = 0; j < numViews; ++j)
2016 {
Martin Radev67a8a012017-09-08 13:03:52 +03002017 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03002018 }
2019 for (int j = numViews; j < 4; ++j)
2020 {
2021 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, view));
2022 }
2023 }
2024
2025 glDeleteProgram(program);
2026 }
2027}
2028
Martin Radev72b4e1e2017-08-31 15:42:56 +03002029// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
2030TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
2031{
2032 if (!requestMultiviewExtension())
2033 {
2034 return;
2035 }
2036
2037 const std::string vsSource =
2038 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002039 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002040 "layout(num_views = 3) in;\n"
2041 "in vec3 vPosition;\n"
2042 "void main()\n"
2043 "{\n"
2044 " gl_Position = vec4(vPosition, 1.);\n"
2045 "}\n";
2046
2047 const std::string fsSource =
2048 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002049 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002050 "precision mediump float;\n"
2051 "out vec4 col;\n"
2052 "void main()\n"
2053 "{\n"
2054 " if (gl_ViewID_OVR == 0u) {\n"
2055 " col = vec4(1,0,0,1);\n"
2056 " } else if (gl_ViewID_OVR == 1u) {\n"
2057 " col = vec4(0,1,0,1);\n"
2058 " } else if (gl_ViewID_OVR == 2u) {\n"
2059 " col = vec4(0,0,1,1);\n"
2060 " } else {\n"
2061 " col = vec4(0,0,0,0);\n"
2062 " }\n"
2063 "}\n";
2064
Olli Etuaho4836acc2018-08-20 15:23:18 +03002065 updateFBOs(1, 1, 3);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002066 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002067
2068 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2069 ASSERT_GL_NO_ERROR();
2070
2071 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2072 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2073 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
2074}
2075
2076// The test checks that the inactive layers of a 2D texture array are not written to by a
2077// multi-view program.
2078TEST_P(MultiviewLayeredRenderTest, RenderToSubrageOfLayers)
2079{
2080 if (!requestMultiviewExtension())
2081 {
2082 return;
2083 }
2084
2085 const std::string vsSource =
2086 "#version 300 es\n"
2087 "#extension GL_OVR_multiview : require\n"
2088 "layout(num_views = 2) in;\n"
2089 "in vec3 vPosition;\n"
2090 "void main()\n"
2091 "{\n"
2092 " gl_Position = vec4(vPosition, 1.);\n"
2093 "}\n";
2094
2095 const std::string fsSource =
2096 "#version 300 es\n"
2097 "#extension GL_OVR_multiview : require\n"
2098 "precision mediump float;\n"
2099 "out vec4 col;\n"
2100 "void main()\n"
2101 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002102 " col = vec4(0,1,0,1);\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002103 "}\n";
2104
Olli Etuaho4836acc2018-08-20 15:23:18 +03002105 updateFBOs(1, 1, 2, 4, 1);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002106 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002107
2108 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2109 ASSERT_GL_NO_ERROR();
2110
2111 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +03002112 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2113 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002114 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
2115}
2116
Martin Radevc1d4e552017-08-21 12:01:10 +03002117// The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
2118// potential bugs if the view is selected in the VS. The test contains a program in which the
2119// gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
2120// fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
2121// never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
2122// green for view 1.
2123TEST_P(MultiviewRenderTest, FlatInterpolation)
Martin Radev3c25ad02017-08-22 17:36:53 +03002124{
Martin Radevc1d4e552017-08-21 12:01:10 +03002125 if (!requestMultiviewExtension())
2126 {
2127 return;
2128 }
2129
2130 const std::string vsSource =
2131 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002132 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002133 "layout(num_views = 2) in;\n"
2134 "in vec3 vPosition;\n"
2135 "flat out int oInstanceID;\n"
2136 "void main()\n"
2137 "{\n"
2138 " gl_Position = vec4(vPosition, 1.);\n"
2139 " oInstanceID = gl_InstanceID;\n"
2140 "}\n";
2141
2142 const std::string fsSource =
2143 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002144 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002145 "precision mediump float;\n"
2146 "flat in int oInstanceID;\n"
2147 "out vec4 col;\n"
2148 "void main()\n"
2149 "{\n"
2150 " if (oInstanceID < 0) {\n"
2151 " discard;\n"
2152 " }\n"
2153 " if (gl_ViewID_OVR == 0u) {\n"
2154 " col = vec4(1,0,0,1);\n"
2155 " } else {\n"
2156 " col = vec4(0,1,0,1);\n"
2157 " }\n"
2158 "}\n";
2159
Olli Etuaho4836acc2018-08-20 15:23:18 +03002160 updateFBOs(1, 1, 2);
Martin Radevc1d4e552017-08-21 12:01:10 +03002161 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2162
2163 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2164 ASSERT_GL_NO_ERROR();
2165
2166 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2167 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +03002168}
2169
Olli Etuaho604d8732018-07-20 11:02:43 +03002170// This test assigns gl_ViewID_OVR to a flat int varying and then sets the color based on that
2171// varying in the fragment shader.
2172TEST_P(MultiviewRenderTest, FlatInterpolation2)
2173{
2174 if (!requestMultiviewExtension())
2175 {
2176 return;
2177 }
2178
2179 const std::string vsSource =
2180 "#version 300 es\n"
2181 "#extension GL_OVR_multiview : require\n"
2182 "layout(num_views = 2) in;\n"
2183 "in vec3 vPosition;\n"
2184 "flat out int flatVarying;\n"
2185 "void main()\n"
2186 "{\n"
2187 " gl_Position = vec4(vPosition, 1.);\n"
2188 " flatVarying = int(gl_ViewID_OVR);\n"
2189 "}\n";
2190
2191 const std::string fsSource =
2192 "#version 300 es\n"
2193 "#extension GL_OVR_multiview : require\n"
2194 "precision mediump float;\n"
2195 "flat in int flatVarying;\n"
2196 "out vec4 col;\n"
2197 "void main()\n"
2198 "{\n"
2199 " if (flatVarying == 0) {\n"
2200 " col = vec4(1,0,0,1);\n"
2201 " } else {\n"
2202 " col = vec4(0,1,0,1);\n"
2203 " }\n"
2204 "}\n";
2205
Olli Etuaho4836acc2018-08-20 15:23:18 +03002206 updateFBOs(1, 1, 2);
Olli Etuaho604d8732018-07-20 11:02:43 +03002207 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2208
2209 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2210 ASSERT_GL_NO_ERROR();
2211
2212 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2213 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2214}
2215
Martin Radev265a6d42017-09-12 16:51:37 +03002216// The test is added to cover a bug which resulted in the viewport/scissor and viewport offsets not
2217// being correctly applied.
2218TEST_P(MultiviewSideBySideRenderTest, ViewportOffsetsAppliedBugCoverage)
2219{
2220 if (!requestMultiviewExtension())
2221 {
2222 return;
2223 }
2224
Olli Etuaho4836acc2018-08-20 15:23:18 +03002225 updateFBOs(1, 1, 2);
Martin Radev265a6d42017-09-12 16:51:37 +03002226
2227 // Create multiview program.
2228 const std::string &vs =
2229 "#version 300 es\n"
2230 "#extension GL_OVR_multiview : require\n"
2231 "layout(num_views = 2) in;\n"
2232 "layout(location = 0) in vec3 vPosition;\n"
2233 "void main()\n"
2234 "{\n"
2235 " gl_Position = vec4(vPosition, 1.0);\n"
2236 "}\n";
2237
2238 const std::string &fs =
2239 "#version 300 es\n"
2240 "#extension GL_OVR_multiview : require\n"
2241 "precision mediump float;\n"
2242 "out vec4 col;\n"
2243 "void main()\n"
2244 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002245 " col = vec4(0,1,0,1);\n"
Martin Radev265a6d42017-09-12 16:51:37 +03002246 "}\n";
2247
2248 ANGLE_GL_PROGRAM(program, vs, fs);
2249
2250 glViewport(0, 0, 1, 1);
2251 glScissor(0, 0, 1, 1);
2252 glEnable(GL_SCISSOR_TEST);
2253 glClearColor(0, 0, 0, 1);
2254
2255 // Bind the default FBO and make sure that the state is synchronized.
2256 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
2257 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2258 ASSERT_GL_NO_ERROR();
2259
2260 // Draw and check that both views are rendered to.
Olli Etuaho4836acc2018-08-20 15:23:18 +03002261 bindMemberDrawFramebuffer();
Martin Radev265a6d42017-09-12 16:51:37 +03002262 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev67a8a012017-09-08 13:03:52 +03002263
Martin Radev265a6d42017-09-12 16:51:37 +03002264 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
Martin Radev67a8a012017-09-08 13:03:52 +03002265 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
2266 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev265a6d42017-09-12 16:51:37 +03002267}
2268
Olli Etuahof26b27e2018-08-17 11:01:19 +03002269MultiviewRenderTestParams SideBySideVertexShaderOpenGL(GLint majorVersion = 3,
2270 GLint minorVersion = 0)
Martin Radev3c25ad02017-08-22 17:36:53 +03002271{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002272 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE,
2273 VertexShaderOpenGL(majorVersion, minorVersion));
Martin Radev3c25ad02017-08-22 17:36:53 +03002274}
2275
Olli Etuahof26b27e2018-08-17 11:01:19 +03002276MultiviewRenderTestParams LayeredVertexShaderOpenGL()
Martin Radev3c25ad02017-08-22 17:36:53 +03002277{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002278 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
2279 VertexShaderOpenGL(3, 0));
Martin Radev3c25ad02017-08-22 17:36:53 +03002280}
2281
Olli Etuahof26b27e2018-08-17 11:01:19 +03002282MultiviewRenderTestParams SideBySideGeomShaderD3D11()
Martin Radev72b4e1e2017-08-31 15:42:56 +03002283{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002284 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE,
2285 GeomShaderD3D11(3, 0));
Martin Radevc1d4e552017-08-21 12:01:10 +03002286}
2287
Olli Etuahof26b27e2018-08-17 11:01:19 +03002288MultiviewRenderTestParams LayeredGeomShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002289{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002290 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, GeomShaderD3D11(3, 0));
Martin Radevc1d4e552017-08-21 12:01:10 +03002291}
2292
Olli Etuahof26b27e2018-08-17 11:01:19 +03002293MultiviewRenderTestParams SideBySideVertexShaderD3D11(GLint majorVersion = 3,
2294 GLint minorVersion = 0)
Martin Radevc1d4e552017-08-21 12:01:10 +03002295{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002296 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE,
2297 VertexShaderD3D11(majorVersion, minorVersion));
Martin Radevc1d4e552017-08-21 12:01:10 +03002298}
2299
Olli Etuahof26b27e2018-08-17 11:01:19 +03002300MultiviewRenderTestParams LayeredVertexShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002301{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002302 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
2303 VertexShaderD3D11(3, 0));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002304}
2305
Jamie Madill04c084d2018-08-08 15:49:28 -04002306ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest,
Olli Etuaho44ae8992018-08-20 15:37:09 +03002307 VertexShaderOpenGL(3, 1),
2308 VertexShaderD3D11(3, 1));
Martin Radevced5c862017-08-17 16:05:29 +03002309ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002310 SideBySideVertexShaderOpenGL(),
2311 LayeredVertexShaderOpenGL(),
2312 SideBySideGeomShaderD3D11(),
2313 SideBySideVertexShaderD3D11(),
2314 LayeredGeomShaderD3D11(),
2315 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002316ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002317 SideBySideVertexShaderOpenGL(),
2318 LayeredVertexShaderOpenGL(),
2319 SideBySideGeomShaderD3D11(),
2320 SideBySideVertexShaderD3D11(),
2321 LayeredGeomShaderD3D11(),
2322 LayeredVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002323ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002324 SideBySideVertexShaderOpenGL(),
2325 LayeredVertexShaderOpenGL(),
2326 SideBySideGeomShaderD3D11(),
2327 SideBySideVertexShaderD3D11(),
2328 LayeredGeomShaderD3D11(),
2329 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002330ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
Olli Etuaho4bcaf992018-08-17 17:18:28 +03002331 VertexShaderOpenGL(3, 0),
2332 GeomShaderD3D11(3, 0),
2333 VertexShaderD3D11(3, 0));
Martin Radevced5c862017-08-17 16:05:29 +03002334ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002335 SideBySideVertexShaderOpenGL(),
2336 LayeredVertexShaderOpenGL(),
2337 SideBySideGeomShaderD3D11(),
2338 SideBySideVertexShaderD3D11(),
2339 LayeredGeomShaderD3D11(),
2340 LayeredVertexShaderD3D11());
Jamie Madill04c084d2018-08-08 15:49:28 -04002341ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest,
2342 VertexShaderOpenGL(3, 0),
2343 GeomShaderD3D11(3, 0));
2344ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, VertexShaderOpenGL(3, 0), GeomShaderD3D11(3, 0));