blob: 40390b2fb314fb9f16d7f491d881f25409237a55 [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{
Mingyu Hu7d64c482019-03-12 14:27:40 -070039 MultiviewRenderTestParams(int samples,
Olli Etuahof26b27e2018-08-17 11:01:19 +030040 const MultiviewImplementationParams &implementationParams)
Mingyu Hu7d64c482019-03-12 14:27:40 -070041 : MultiviewImplementationParams(implementationParams), mSamples(samples)
42 {}
Olli Etuaho2c8f0842018-09-12 14:44:55 +030043 int mSamples;
Martin Radev3c25ad02017-08-22 17:36:53 +030044};
45
Olli Etuahof26b27e2018-08-17 11:01:19 +030046std::ostream &operator<<(std::ostream &os, const MultiviewRenderTestParams &params)
Martin Radev3c25ad02017-08-22 17:36:53 +030047{
Martin Radevc1d4e552017-08-21 12:01:10 +030048 const MultiviewImplementationParams &base =
49 static_cast<const MultiviewImplementationParams &>(params);
Martin Radev3c25ad02017-08-22 17:36:53 +030050 os << base;
Mingyu Hu7d64c482019-03-12 14:27:40 -070051 os << "_layered";
52
Olli Etuaho2c8f0842018-09-12 14:44:55 +030053 if (params.mSamples > 0)
54 {
55 os << "_samples_" << params.mSamples;
56 }
Martin Radev3c25ad02017-08-22 17:36:53 +030057 return os;
58}
59
Olli Etuaho4836acc2018-08-20 15:23:18 +030060class MultiviewFramebufferTestBase : public MultiviewTestBase
Martin Radev8f276e22017-05-30 12:05:52 +030061{
62 protected:
Mingyu Hu7d64c482019-03-12 14:27:40 -070063 MultiviewFramebufferTestBase(const PlatformParameters &params, int samples)
Olli Etuahof26b27e2018-08-17 11:01:19 +030064 : MultiviewTestBase(params),
Martin Radev3c25ad02017-08-22 17:36:53 +030065 mViewWidth(0),
66 mViewHeight(0),
Olli Etuaho4836acc2018-08-20 15:23:18 +030067 mNumViews(0),
Olli Etuaho44ae8992018-08-20 15:37:09 +030068 mColorTexture(0u),
69 mDepthTexture(0u),
70 mDrawFramebuffer(0u),
Olli Etuaho2c8f0842018-09-12 14:44:55 +030071 mSamples(samples),
72 mResolveTexture(0u)
Jamie Madillb980c562018-11-27 11:34:27 -050073 {}
Olli Etuaho44ae8992018-08-20 15:37:09 +030074
Olli Etuaho4836acc2018-08-20 15:23:18 +030075 void FramebufferTestSetUp() { MultiviewTestBase::MultiviewTestBaseSetUp(); }
Olli Etuaho44ae8992018-08-20 15:37:09 +030076
77 void FramebufferTestTearDown()
78 {
79 freeFBOs();
80 MultiviewTestBase::MultiviewTestBaseTearDown();
81 }
82
Olli Etuaho4836acc2018-08-20 15:23:18 +030083 void updateFBOs(int viewWidth, int height, int numViews, int numLayers, int baseViewIndex)
Martin Radev3c25ad02017-08-22 17:36:53 +030084 {
Jamie Madillba319ba2018-12-29 10:29:33 -050085 ASSERT_TRUE(numViews + baseViewIndex <= numLayers);
Martin Radev72b4e1e2017-08-31 15:42:56 +030086
Olli Etuaho44ae8992018-08-20 15:37:09 +030087 freeFBOs();
88
Martin Radev3c25ad02017-08-22 17:36:53 +030089 mViewWidth = viewWidth;
90 mViewHeight = height;
91 mNumViews = numViews;
Martin Radev8f276e22017-05-30 12:05:52 +030092
Olli Etuaho44ae8992018-08-20 15:37:09 +030093 glGenTextures(1, &mColorTexture);
94 glGenTextures(1, &mDepthTexture);
Martin Radev0abb7a22017-08-28 15:34:45 +030095
Mingyu Hu7d64c482019-03-12 14:27:40 -070096 CreateMultiviewBackingTextures(mSamples, viewWidth, height, numLayers, mColorTexture,
97 mDepthTexture, 0u);
Martin Radev3c25ad02017-08-22 17:36:53 +030098
Olli Etuaho44ae8992018-08-20 15:37:09 +030099 glGenFramebuffers(1, &mDrawFramebuffer);
100
Martin Radev3c25ad02017-08-22 17:36:53 +0300101 // Create draw framebuffer to be used for multiview rendering.
102 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700103 AttachMultiviewTextures(GL_DRAW_FRAMEBUFFER, viewWidth, numViews, baseViewIndex,
104 mColorTexture, mDepthTexture, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300105
Martin Radev8f276e22017-05-30 12:05:52 +0300106 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
107
108 // Create read framebuffer to be used to retrieve the pixel information for testing
109 // purposes.
Mingyu Hu7d64c482019-03-12 14:27:40 -0700110 mReadFramebuffer.resize(numLayers);
111 glGenFramebuffers(static_cast<GLsizei>(mReadFramebuffer.size()), mReadFramebuffer.data());
112 for (int i = 0; i < numLayers; ++i)
Martin Radev3c25ad02017-08-22 17:36:53 +0300113 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700114 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
115 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mColorTexture, 0,
116 i);
117 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
118 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300119 }
Martin Radev8f276e22017-05-30 12:05:52 +0300120
121 // Clear the buffers.
Martin Radev3c25ad02017-08-22 17:36:53 +0300122 glViewport(0, 0, viewWidth, height);
Martin Radev3c25ad02017-08-22 17:36:53 +0300123 }
Martin Radev8f276e22017-05-30 12:05:52 +0300124
Olli Etuaho4836acc2018-08-20 15:23:18 +0300125 void updateFBOs(int viewWidth, int height, int numViews)
Martin Radev72b4e1e2017-08-31 15:42:56 +0300126 {
Olli Etuaho4836acc2018-08-20 15:23:18 +0300127 updateFBOs(viewWidth, height, numViews, numViews, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300128 }
129
Olli Etuaho4836acc2018-08-20 15:23:18 +0300130 void bindMemberDrawFramebuffer() { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer); }
131
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300132 // In case we have a multisampled framebuffer, creates and binds a resolve framebuffer as the
133 // draw framebuffer, and resolves the read framebuffer to it.
134 void resolveMultisampledFBO()
135 {
136 if (mSamples == 0)
137 {
138 return;
139 }
140 int numLayers = mReadFramebuffer.size();
141 if (mResolveFramebuffer.empty())
142 {
Jamie Madillba319ba2018-12-29 10:29:33 -0500143 ASSERT_TRUE(mResolveTexture == 0u);
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300144 glGenTextures(1, &mResolveTexture);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700145 CreateMultiviewBackingTextures(0, mViewWidth, mViewHeight, numLayers, mResolveTexture,
146 0u, 0u);
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300147
148 mResolveFramebuffer.resize(numLayers);
149 glGenFramebuffers(static_cast<GLsizei>(mResolveFramebuffer.size()),
150 mResolveFramebuffer.data());
151 for (int i = 0; i < numLayers; ++i)
152 {
153 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFramebuffer[i]);
154 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
155 mResolveTexture, 0, i);
156 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
157 glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
158 }
159 }
160 for (int i = 0; i < numLayers; ++i)
161 {
162 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
163 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFramebuffer[i]);
164 glBlitFramebuffer(0, 0, mViewWidth, mViewHeight, 0, 0, mViewWidth, mViewHeight,
165 GL_COLOR_BUFFER_BIT, GL_NEAREST);
166 }
167 }
168
Martin Radev3c25ad02017-08-22 17:36:53 +0300169 GLColor GetViewColor(int x, int y, int view)
170 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700171 EXPECT_TRUE(static_cast<size_t>(view) < mReadFramebuffer.size());
172 if (mSamples > 0)
Martin Radev3c25ad02017-08-22 17:36:53 +0300173 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700174 EXPECT_TRUE(static_cast<size_t>(view) < mResolveFramebuffer.size());
175 glBindFramebuffer(GL_READ_FRAMEBUFFER, mResolveFramebuffer[view]);
Martin Radev3c25ad02017-08-22 17:36:53 +0300176 }
Mingyu Hu7d64c482019-03-12 14:27:40 -0700177 else
178 {
179 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
180 }
181 return ReadColor(x, y);
Martin Radev8f276e22017-05-30 12:05:52 +0300182 }
183
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300184 bool isMultisampled() { return mSamples > 0; }
185
Martin Radev3c25ad02017-08-22 17:36:53 +0300186 int mViewWidth;
187 int mViewHeight;
188 int mNumViews;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300189
Olli Etuaho44ae8992018-08-20 15:37:09 +0300190 GLuint mColorTexture;
191 GLuint mDepthTexture;
192
Olli Etuaho4836acc2018-08-20 15:23:18 +0300193 private:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300194 GLuint mDrawFramebuffer;
195 std::vector<GLuint> mReadFramebuffer;
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300196 int mSamples;
197
198 // For reading back multisampled framebuffer.
199 std::vector<GLuint> mResolveFramebuffer;
200 GLuint mResolveTexture;
Olli Etuaho44ae8992018-08-20 15:37:09 +0300201
202 void freeFBOs()
203 {
204 if (mDrawFramebuffer)
205 {
206 glDeleteFramebuffers(1, &mDrawFramebuffer);
207 mDrawFramebuffer = 0;
208 }
209 if (!mReadFramebuffer.empty())
210 {
Shahbaz Youssefic4097442018-08-22 12:14:52 -0400211 GLsizei framebufferCount = static_cast<GLsizei>(mReadFramebuffer.size());
212 glDeleteFramebuffers(framebufferCount, mReadFramebuffer.data());
Olli Etuaho44ae8992018-08-20 15:37:09 +0300213 mReadFramebuffer.clear();
214 }
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300215 if (!mResolveFramebuffer.empty())
216 {
217 GLsizei framebufferCount = static_cast<GLsizei>(mResolveFramebuffer.size());
218 glDeleteFramebuffers(framebufferCount, mResolveFramebuffer.data());
219 mResolveFramebuffer.clear();
220 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300221 if (mDepthTexture)
222 {
223 glDeleteTextures(1, &mDepthTexture);
224 mDepthTexture = 0;
225 }
226 if (mColorTexture)
227 {
228 glDeleteTextures(1, &mColorTexture);
229 mColorTexture = 0;
230 }
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300231 if (mResolveTexture)
232 {
233 glDeleteTextures(1, &mResolveTexture);
234 mResolveTexture = 0;
235 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300236 }
Martin Radev8f276e22017-05-30 12:05:52 +0300237};
238
Olli Etuaho4836acc2018-08-20 15:23:18 +0300239class MultiviewRenderTest : public MultiviewFramebufferTestBase,
Olli Etuahof26b27e2018-08-17 11:01:19 +0300240 public ::testing::TestWithParam<MultiviewRenderTestParams>
Martin Radev8f276e22017-05-30 12:05:52 +0300241{
242 protected:
Mingyu Hu7d64c482019-03-12 14:27:40 -0700243 MultiviewRenderTest() : MultiviewFramebufferTestBase(GetParam(), GetParam().mSamples) {}
Martin Radevc1d4e552017-08-21 12:01:10 +0300244
245 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
246 {
247 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
248 }
Jamie Madill5cbaa3f2019-05-07 15:49:22 -0400249
250 virtual void testSetUp() {}
251 virtual void testTearDown() {}
252
253 private:
254 void SetUp() override
255 {
256 MultiviewFramebufferTestBase::FramebufferTestSetUp();
257 testSetUp();
258 }
259 void TearDown() override
260 {
261 testTearDown();
262 MultiviewFramebufferTestBase::FramebufferTestTearDown();
263 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300264};
265
Jamie Madill04c084d2018-08-08 15:49:28 -0400266constexpr char kDualViewVSSource[] = R"(#version 300 es
Mingyu Hu7d64c482019-03-12 14:27:40 -0700267#extension GL_OVR_multiview2 : require
Jamie Madill04c084d2018-08-08 15:49:28 -0400268layout(num_views = 2) in;
269in vec4 vPosition;
270void main()
271{
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300272 gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x * 0.5 + 0.5 : vPosition.x * 0.5 - 0.5);
Jamie Madill04c084d2018-08-08 15:49:28 -0400273 gl_Position.yzw = vPosition.yzw;
274})";
275
276constexpr char kDualViewFSSource[] = R"(#version 300 es
Mingyu Hu7d64c482019-03-12 14:27:40 -0700277#extension GL_OVR_multiview2 : require
Jamie Madill04c084d2018-08-08 15:49:28 -0400278precision mediump float;
279out vec4 col;
280void main()
281{
282 col = vec4(0,1,0,1);
283})";
284
Martin Radev3c25ad02017-08-22 17:36:53 +0300285class MultiviewRenderDualViewTest : public MultiviewRenderTest
286{
287 protected:
288 MultiviewRenderDualViewTest() : mProgram(0u) {}
Martin Radev8f276e22017-05-30 12:05:52 +0300289
Jamie Madill5cbaa3f2019-05-07 15:49:22 -0400290 void testSetUp() override
Martin Radev8f276e22017-05-30 12:05:52 +0300291 {
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300292 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +0300293 {
294 return;
295 }
296
Olli Etuaho4836acc2018-08-20 15:23:18 +0300297 updateFBOs(2, 1, 2);
Jamie Madill04c084d2018-08-08 15:49:28 -0400298 mProgram = CompileProgram(kDualViewVSSource, kDualViewFSSource);
Martin Radev61bd9992017-08-11 13:10:55 +0300299 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300300 glUseProgram(mProgram);
301 ASSERT_GL_NO_ERROR();
302 }
303
Jamie Madill5cbaa3f2019-05-07 15:49:22 -0400304 void testTearDown() override
Olli Etuaho44ae8992018-08-20 15:37:09 +0300305 {
306 if (mProgram != 0u)
307 {
308 glDeleteProgram(mProgram);
309 mProgram = 0u;
310 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300311 }
312
Martin Radev8f276e22017-05-30 12:05:52 +0300313 void checkOutput()
314 {
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300315 resolveMultisampledFBO();
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300316 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +0300317 EXPECT_EQ(GLColor::green, GetViewColor(1, 0, 0));
318 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300319 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(1, 0, 1));
Martin Radev8f276e22017-05-30 12:05:52 +0300320 }
321
322 GLuint mProgram;
323};
324
Olli Etuaho44ae8992018-08-20 15:37:09 +0300325// Base class for tests that care mostly about draw call validity and not rendering results.
326class MultiviewDrawValidationTest : public MultiviewTest
Jamie Madill04c084d2018-08-08 15:49:28 -0400327{
328 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300329 MultiviewDrawValidationTest() : MultiviewTest() {}
Jamie Madill04c084d2018-08-08 15:49:28 -0400330
Mingyu Hu7d64c482019-03-12 14:27:40 -0700331 void initOnePixelColorTexture2DSingleLayered(GLuint texId)
Jamie Madill04c084d2018-08-08 15:49:28 -0400332 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700333 glBindTexture(GL_TEXTURE_2D_ARRAY, texId);
334 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
335 nullptr);
336 }
337
338 void initOnePixelColorTexture2DMultiLayered(GLuint texId)
339 {
340 glBindTexture(GL_TEXTURE_2D_ARRAY, texId);
341 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
342 nullptr);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300343 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400344
Olli Etuaho44ae8992018-08-20 15:37:09 +0300345 // This initializes a simple VAO with a valid vertex buffer and index buffer with three
346 // vertices.
347 void initVAO(GLuint vao, GLuint vertexBuffer, GLuint indexBuffer)
348 {
349 glBindVertexArray(vao);
Jamie Madill04c084d2018-08-08 15:49:28 -0400350
351 const float kVertexData[3] = {0.0f};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300352 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400353 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
354
355 const unsigned int kIndices[3] = {0u, 1u, 2u};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300356 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400357 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
358 GL_STATIC_DRAW);
359 ASSERT_GL_NO_ERROR();
360 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400361};
362
Martin Radev3c25ad02017-08-22 17:36:53 +0300363class MultiviewOcclusionQueryTest : public MultiviewRenderTest
Martin Radev0d671c92017-08-10 16:41:52 +0300364{
365 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300366 MultiviewOcclusionQueryTest() {}
Martin Radev0d671c92017-08-10 16:41:52 +0300367
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400368 bool requestOcclusionQueryExtension()
369 {
Jamie Madillb8149072019-04-30 16:14:44 -0400370 if (IsGLExtensionRequestable("GL_EXT_occlusion_query_boolean"))
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400371 {
372 glRequestExtensionANGLE("GL_EXT_occlusion_query_boolean");
373 }
374
Jamie Madillb8149072019-04-30 16:14:44 -0400375 if (!IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"))
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400376 {
377 std::cout << "Test skipped due to missing GL_EXT_occlusion_query_boolean." << std::endl;
378 return false;
379 }
380 return true;
381 }
382
Martin Radev0d671c92017-08-10 16:41:52 +0300383 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
384 {
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400385 GLQueryEXT query;
386 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED, query);
Martin Radev0d671c92017-08-10 16:41:52 +0300387 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
388 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
389
390 GLuint result = GL_TRUE;
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400391 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT, &result);
Martin Radev0d671c92017-08-10 16:41:52 +0300392 return result;
393 }
394};
395
Olli Etuaho4bcaf992018-08-17 17:18:28 +0300396class MultiviewProgramGenerationTest : public MultiviewTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300397{
398 protected:
399 MultiviewProgramGenerationTest() {}
400};
401
Martin Radev3c25ad02017-08-22 17:36:53 +0300402class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300403{
404 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300405 MultiviewRenderPrimitiveTest() : mVBO(0u) {}
406
Jamie Madill5cbaa3f2019-05-07 15:49:22 -0400407 void testSetUp() override { glGenBuffers(1, &mVBO); }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300408
Jamie Madill5cbaa3f2019-05-07 15:49:22 -0400409 void testTearDown() override
Olli Etuaho44ae8992018-08-20 15:37:09 +0300410 {
411 if (mVBO)
412 {
413 glDeleteBuffers(1, &mVBO);
414 mVBO = 0u;
415 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300416 }
Martin Radev61bd9992017-08-11 13:10:55 +0300417
418 void setupGeometry(const std::vector<Vector2> &vertexData)
419 {
Martin Radev61bd9992017-08-11 13:10:55 +0300420 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
421 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
422 GL_STATIC_DRAW);
423 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500424 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +0300425 }
426
Martin Radev67a8a012017-09-08 13:03:52 +0300427 void checkGreenChannel(const GLubyte expectedGreenChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300428 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300429 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300430 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300431 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300432 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300433 for (int h = 0; h < mViewHeight; ++h)
434 {
435 size_t flatIndex =
436 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300437 EXPECT_EQ(GLColor(0, expectedGreenChannelData[flatIndex], 0,
438 expectedGreenChannelData[flatIndex]),
Martin Radev3c25ad02017-08-22 17:36:53 +0300439 GetViewColor(w, h, view));
440 }
Martin Radev61bd9992017-08-11 13:10:55 +0300441 }
442 }
443 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300444 GLuint mVBO;
Martin Radev61bd9992017-08-11 13:10:55 +0300445};
446
Olli Etuaho4836acc2018-08-20 15:23:18 +0300447class MultiviewLayeredRenderTest : public MultiviewFramebufferTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300448 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev72b4e1e2017-08-31 15:42:56 +0300449{
450 protected:
Mingyu Hu7d64c482019-03-12 14:27:40 -0700451 MultiviewLayeredRenderTest() : MultiviewFramebufferTestBase(GetParam(), 0) {}
Olli Etuaho44ae8992018-08-20 15:37:09 +0300452 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
453 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
454 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
Martin Radevc1d4e552017-08-21 12:01:10 +0300455 {
456 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
457 }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300458};
459
Mingyu Hu7d64c482019-03-12 14:27:40 -0700460// The test verifies that glDraw*Indirect works for any number of views.
Martin Radev7cf61662017-07-26 17:10:53 +0300461TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300462{
Jamie Madill3a256222018-12-08 09:56:39 -0500463 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radev14a26ae2017-07-24 15:56:29 +0300464
Jamie Madill35cd7332018-12-02 12:03:33 -0500465 constexpr char kFS[] =
Martin Radev14a26ae2017-07-24 15:56:29 +0300466 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700467 "#extension GL_OVR_multiview2 : require\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300468 "precision mediump float;\n"
shrekshao15ce8222019-03-18 19:25:21 -0700469 "out vec4 color;\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300470 "void main()\n"
shrekshao15ce8222019-03-18 19:25:21 -0700471 "{color = vec4(1);}\n";
Martin Radev14a26ae2017-07-24 15:56:29 +0300472
Olli Etuaho44ae8992018-08-20 15:37:09 +0300473 GLVertexArray vao;
474 GLBuffer vertexBuffer;
475 GLBuffer indexBuffer;
476 initVAO(vao, vertexBuffer, indexBuffer);
477
478 GLFramebuffer fbo;
479 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
480
Martin Radev14a26ae2017-07-24 15:56:29 +0300481 GLBuffer commandBuffer;
482 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
483 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
484 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
485 ASSERT_GL_NO_ERROR();
486
Mingyu Hu7d64c482019-03-12 14:27:40 -0700487 // Check that no errors are generated with the framebuffer having 2 views.
Martin Radev14a26ae2017-07-24 15:56:29 +0300488 {
Jamie Madill35cd7332018-12-02 12:03:33 -0500489 constexpr char kVS[] =
Martin Radev14a26ae2017-07-24 15:56:29 +0300490 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700491 "#extension GL_OVR_multiview2 : require\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300492 "layout(num_views = 2) in;\n"
493 "void main()\n"
494 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500495 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev14a26ae2017-07-24 15:56:29 +0300496 glUseProgram(program);
497
Mingyu Hu7d64c482019-03-12 14:27:40 -0700498 GLTexture tex2DArray;
499 initOnePixelColorTexture2DMultiLayered(tex2DArray);
500
501 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radev14a26ae2017-07-24 15:56:29 +0300502
503 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700504 EXPECT_GL_NO_ERROR();
Martin Radev14a26ae2017-07-24 15:56:29 +0300505
506 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700507 EXPECT_GL_NO_ERROR();
Martin Radev14a26ae2017-07-24 15:56:29 +0300508 }
509
510 // Check that no errors are generated if the number of views is 1.
511 {
Jamie Madill35cd7332018-12-02 12:03:33 -0500512 constexpr char kVS[] =
Martin Radev14a26ae2017-07-24 15:56:29 +0300513 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700514 "#extension GL_OVR_multiview2 : require\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300515 "layout(num_views = 1) in;\n"
516 "void main()\n"
517 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500518 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev14a26ae2017-07-24 15:56:29 +0300519 glUseProgram(program);
520
Mingyu Hu7d64c482019-03-12 14:27:40 -0700521 GLTexture tex2D;
522 initOnePixelColorTexture2DSingleLayered(tex2D);
523
524 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Martin Radev14a26ae2017-07-24 15:56:29 +0300525
526 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
527 EXPECT_GL_NO_ERROR();
528
529 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
530 EXPECT_GL_NO_ERROR();
531 }
532}
533
Martin Radev7cf61662017-07-26 17:10:53 +0300534// The test verifies that glDraw*:
535// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
536// program differs.
537// 2) does not generate any error if the number of views is the same.
Martin Radev7cf61662017-07-26 17:10:53 +0300538TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
539{
Jamie Madill3a256222018-12-08 09:56:39 -0500540 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radev7cf61662017-07-26 17:10:53 +0300541
Jamie Madill35cd7332018-12-02 12:03:33 -0500542 constexpr char kVS[] =
Martin Radev7cf61662017-07-26 17:10:53 +0300543 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700544 "#extension GL_OVR_multiview2 : require\n"
Martin Radev7cf61662017-07-26 17:10:53 +0300545 "layout(num_views = 2) in;\n"
546 "void main()\n"
547 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500548 constexpr char kFS[] =
Martin Radev7cf61662017-07-26 17:10:53 +0300549 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700550 "#extension GL_OVR_multiview2 : require\n"
Martin Radev7cf61662017-07-26 17:10:53 +0300551 "precision mediump float;\n"
shrekshao15ce8222019-03-18 19:25:21 -0700552 "out vec4 color;\n"
Martin Radev7cf61662017-07-26 17:10:53 +0300553 "void main()\n"
shrekshao15ce8222019-03-18 19:25:21 -0700554 "{color = vec4(1);}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500555 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev7cf61662017-07-26 17:10:53 +0300556 glUseProgram(program);
557
Olli Etuaho44ae8992018-08-20 15:37:09 +0300558 GLVertexArray vao;
559 GLBuffer vertexBuffer;
560 GLBuffer indexBuffer;
561 initVAO(vao, vertexBuffer, indexBuffer);
562
563 GLFramebuffer fbo;
564 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
565
Martin Radev7cf61662017-07-26 17:10:53 +0300566 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
567 // number of views.
568 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700569 GLTexture tex2D;
570 initOnePixelColorTexture2DSingleLayered(tex2D);
571
Martin Radev7cf61662017-07-26 17:10:53 +0300572 // The framebuffer has only 1 view.
Mingyu Hu7d64c482019-03-12 14:27:40 -0700573 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Martin Radev7cf61662017-07-26 17:10:53 +0300574
575 glDrawArrays(GL_TRIANGLES, 0, 3);
576 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
577
578 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
579 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
580 }
581
582 // Check that no errors are generated if the number of views in both program and draw
583 // framebuffer matches.
584 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700585 GLTexture tex2DArray;
586 initOnePixelColorTexture2DMultiLayered(tex2DArray);
587
588 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radev7cf61662017-07-26 17:10:53 +0300589
590 glDrawArrays(GL_TRIANGLES, 0, 3);
591 EXPECT_GL_NO_ERROR();
592
593 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
594 EXPECT_GL_NO_ERROR();
595 }
Martin Radevda8e2572017-09-12 17:21:16 +0300596}
Martin Radev7cf61662017-07-26 17:10:53 +0300597
Martin Radevda8e2572017-09-12 17:21:16 +0300598// The test verifies that glDraw* generates an INVALID_OPERATION error if the program does not use
599// the multiview extension, but the active draw framebuffer has more than one view.
600TEST_P(MultiviewDrawValidationTest, NumViewsMismatchForNonMultiviewProgram)
601{
602 if (!requestMultiviewExtension())
Martin Radev7cf61662017-07-26 17:10:53 +0300603 {
Martin Radevda8e2572017-09-12 17:21:16 +0300604 return;
Martin Radev7cf61662017-07-26 17:10:53 +0300605 }
Martin Radevda8e2572017-09-12 17:21:16 +0300606
Jamie Madill35cd7332018-12-02 12:03:33 -0500607 constexpr char kVS[] =
Martin Radevda8e2572017-09-12 17:21:16 +0300608 "#version 300 es\n"
609 "void main()\n"
610 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500611 constexpr char kFS[] =
Martin Radevda8e2572017-09-12 17:21:16 +0300612 "#version 300 es\n"
613 "precision mediump float;\n"
614 "void main()\n"
615 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500616 ANGLE_GL_PROGRAM(programNoMultiview, kVS, kFS);
Martin Radevda8e2572017-09-12 17:21:16 +0300617 glUseProgram(programNoMultiview);
618
Olli Etuaho44ae8992018-08-20 15:37:09 +0300619 GLVertexArray vao;
620 GLBuffer vertexBuffer;
621 GLBuffer indexBuffer;
622 initVAO(vao, vertexBuffer, indexBuffer);
623
624 GLFramebuffer fbo;
625 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
626
Mingyu Hu7d64c482019-03-12 14:27:40 -0700627 GLTexture tex2DArray;
628 initOnePixelColorTexture2DMultiLayered(tex2DArray);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300629
Mingyu Hu7d64c482019-03-12 14:27:40 -0700630 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radevda8e2572017-09-12 17:21:16 +0300631
632 glDrawArrays(GL_TRIANGLES, 0, 3);
633 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
634
635 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
636 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radev7cf61662017-07-26 17:10:53 +0300637}
638
Martin Radev7e69f762017-07-27 14:54:13 +0300639// The test verifies that glDraw*:
640// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
Jamie Madill3a256222018-12-08 09:56:39 -0500641// greater than 1 and there is an active not paused transform feedback object.
Martin Radev7e69f762017-07-27 14:54:13 +0300642// 2) does not generate any error if the number of views in the draw framebuffer is 1.
643TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
644{
Jamie Madill3a256222018-12-08 09:56:39 -0500645 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radev7e69f762017-07-27 14:54:13 +0300646
Jamie Madill35cd7332018-12-02 12:03:33 -0500647 constexpr char kVS[] = R"(#version 300 es
648out float tfVarying;
649void main()
650{
651 tfVarying = 1.0;
652})";
653
654 constexpr char kFS[] = R"(#version 300 es
655precision mediump float;
656void main()
657{})";
Jamie Madill04c084d2018-08-08 15:49:28 -0400658
Olli Etuaho3755c482017-10-13 15:40:26 +0300659 std::vector<std::string> tfVaryings;
Jamie Madill04c084d2018-08-08 15:49:28 -0400660 tfVaryings.emplace_back("tfVarying");
Jamie Madill35cd7332018-12-02 12:03:33 -0500661 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(singleViewProgram, kVS, kFS, tfVaryings,
Olli Etuaho3755c482017-10-13 15:40:26 +0300662 GL_SEPARATE_ATTRIBS);
Jamie Madill04c084d2018-08-08 15:49:28 -0400663
664 std::vector<std::string> dualViewTFVaryings;
665 dualViewTFVaryings.emplace_back("gl_Position");
666 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(dualViewProgram, kDualViewVSSource, kDualViewFSSource,
667 dualViewTFVaryings, GL_SEPARATE_ATTRIBS);
Martin Radev7e69f762017-07-27 14:54:13 +0300668
Olli Etuaho44ae8992018-08-20 15:37:09 +0300669 GLVertexArray vao;
670 GLBuffer vertexBuffer;
671 GLBuffer indexBuffer;
672 initVAO(vao, vertexBuffer, indexBuffer);
673
Martin Radev7e69f762017-07-27 14:54:13 +0300674 GLBuffer tbo;
675 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
Jamie Madill04c084d2018-08-08 15:49:28 -0400676 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 16u, nullptr, GL_STATIC_DRAW);
Martin Radev7e69f762017-07-27 14:54:13 +0300677
678 GLTransformFeedback transformFeedback;
679 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
Olli Etuaho3755c482017-10-13 15:40:26 +0300680
681 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
682
Jamie Madill04c084d2018-08-08 15:49:28 -0400683 glUseProgram(dualViewProgram);
Martin Radev7e69f762017-07-27 14:54:13 +0300684 glBeginTransformFeedback(GL_TRIANGLES);
685 ASSERT_GL_NO_ERROR();
686
Olli Etuaho44ae8992018-08-20 15:37:09 +0300687 GLFramebuffer fbo;
688 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
689
Mingyu Hu7d64c482019-03-12 14:27:40 -0700690 GLTexture tex2DArray;
691 initOnePixelColorTexture2DMultiLayered(tex2DArray);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300692
shrekshao15ce8222019-03-18 19:25:21 -0700693 GLenum bufs[] = {GL_NONE};
694 glDrawBuffers(1, bufs);
695
Martin Radev7e69f762017-07-27 14:54:13 +0300696 // Check that drawArrays generates an error when there is an active transform feedback object
697 // and the number of views in the draw framebuffer is greater than 1.
698 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700699 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radev7e69f762017-07-27 14:54:13 +0300700 glDrawArrays(GL_TRIANGLES, 0, 3);
701 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
702 }
703
Jamie Madill04c084d2018-08-08 15:49:28 -0400704 glEndTransformFeedback();
705
706 // Ending transform feedback should allow the draw to succeed.
707 {
708 glDrawArrays(GL_TRIANGLES, 0, 3);
709 EXPECT_GL_NO_ERROR();
710 }
711
Jamie Madill3a256222018-12-08 09:56:39 -0500712 // A paused transform feedback should not trigger an error.
Jamie Madill04c084d2018-08-08 15:49:28 -0400713 glBeginTransformFeedback(GL_TRIANGLES);
714 glPauseTransformFeedback();
715 ASSERT_GL_NO_ERROR();
716
717 glDrawArrays(GL_TRIANGLES, 0, 3);
Jamie Madill3a256222018-12-08 09:56:39 -0500718 ASSERT_GL_NO_ERROR();
Jamie Madill04c084d2018-08-08 15:49:28 -0400719
720 // Unbind transform feedback - should succeed.
721 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
722 glDrawArrays(GL_TRIANGLES, 0, 3);
723 ASSERT_GL_NO_ERROR();
724
Jamie Madill3a256222018-12-08 09:56:39 -0500725 // Rebind paused transform feedback - should succeed.
Jamie Madill04c084d2018-08-08 15:49:28 -0400726 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
727 glDrawArrays(GL_TRIANGLES, 0, 3);
Jamie Madill3a256222018-12-08 09:56:39 -0500728 ASSERT_GL_NO_ERROR();
Jamie Madill04c084d2018-08-08 15:49:28 -0400729
730 glResumeTransformFeedback();
731 glEndTransformFeedback();
732
733 glUseProgram(singleViewProgram);
734 glBeginTransformFeedback(GL_TRIANGLES);
735 ASSERT_GL_NO_ERROR();
736
Mingyu Hu7d64c482019-03-12 14:27:40 -0700737 GLTexture tex2D;
738 initOnePixelColorTexture2DSingleLayered(tex2D);
739
Martin Radev7e69f762017-07-27 14:54:13 +0300740 // Check that drawArrays does not generate an error when the number of views in the draw
741 // framebuffer is 1.
742 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700743 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Martin Radev7e69f762017-07-27 14:54:13 +0300744 glDrawArrays(GL_TRIANGLES, 0, 3);
745 EXPECT_GL_NO_ERROR();
746 }
747
748 glEndTransformFeedback();
749}
750
Martin Radevffe754b2017-07-31 10:38:07 +0300751// The test verifies that glDraw*:
752// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
753// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
754// 2) does not generate any error if the number of views in the draw framebuffer is 1.
755TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
756{
Yunchao He9550c602018-02-13 14:47:05 +0800757 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Jamie Madillb8149072019-04-30 16:14:44 -0400758 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_disjoint_timer_query"));
Martin Radevffe754b2017-07-31 10:38:07 +0300759
Olli Etuaho44ae8992018-08-20 15:37:09 +0300760 ANGLE_GL_PROGRAM(dualViewProgram, kDualViewVSSource, kDualViewFSSource);
761
Jamie Madill35cd7332018-12-02 12:03:33 -0500762 constexpr char kVS[] =
Martin Radevffe754b2017-07-31 10:38:07 +0300763 "#version 300 es\n"
764 "void main()\n"
765 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500766 constexpr char kFS[] =
Martin Radevffe754b2017-07-31 10:38:07 +0300767 "#version 300 es\n"
768 "precision mediump float;\n"
769 "void main()\n"
770 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500771 ANGLE_GL_PROGRAM(singleViewProgram, kVS, kFS);
Jamie Madill04c084d2018-08-08 15:49:28 -0400772 glUseProgram(singleViewProgram);
Martin Radevffe754b2017-07-31 10:38:07 +0300773
Olli Etuaho44ae8992018-08-20 15:37:09 +0300774 GLVertexArray vao;
775 GLBuffer vertexBuffer;
776 GLBuffer indexBuffer;
777 initVAO(vao, vertexBuffer, indexBuffer);
778
Martin Radevffe754b2017-07-31 10:38:07 +0300779 GLuint query = 0u;
780 glGenQueriesEXT(1, &query);
781 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
782
Olli Etuaho44ae8992018-08-20 15:37:09 +0300783 GLFramebuffer fbo;
784 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
785
Mingyu Hu7d64c482019-03-12 14:27:40 -0700786 GLTexture tex2DArr;
787 initOnePixelColorTexture2DMultiLayered(tex2DArr);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300788
shrekshao15ce8222019-03-18 19:25:21 -0700789 GLenum bufs[] = {GL_NONE};
790 glDrawBuffers(1, bufs);
791
Martin Radevffe754b2017-07-31 10:38:07 +0300792 // Check first case.
793 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300794 glUseProgram(dualViewProgram);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700795 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArr, 0, 0, 2);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300796 glClear(GL_COLOR_BUFFER_BIT);
797 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radevffe754b2017-07-31 10:38:07 +0300798 glDrawArrays(GL_TRIANGLES, 0, 3);
799 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
800 }
801
Mingyu Hu7d64c482019-03-12 14:27:40 -0700802 GLTexture tex2D;
803 initOnePixelColorTexture2DSingleLayered(tex2D);
804
Martin Radevffe754b2017-07-31 10:38:07 +0300805 // Check second case.
806 {
Jamie Madill04c084d2018-08-08 15:49:28 -0400807 glUseProgram(singleViewProgram);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700808 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300809 glClear(GL_COLOR_BUFFER_BIT);
810 EXPECT_GL_NO_ERROR();
Martin Radevffe754b2017-07-31 10:38:07 +0300811 glDrawArrays(GL_TRIANGLES, 0, 3);
812 EXPECT_GL_NO_ERROR();
813 }
814
815 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
816 glDeleteQueries(1, &query);
Jamie Madill04c084d2018-08-08 15:49:28 -0400817
818 // Check starting a query after a successful draw.
819 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300820 glUseProgram(dualViewProgram);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700821 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArr, 0, 0, 2);
Jamie Madill04c084d2018-08-08 15:49:28 -0400822 glClear(GL_COLOR_BUFFER_BIT);
823 EXPECT_GL_NO_ERROR();
824 glDrawArrays(GL_TRIANGLES, 0, 3);
825 EXPECT_GL_NO_ERROR();
826
827 glGenQueriesEXT(1, &query);
828 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
829
830 glDrawArrays(GL_TRIANGLES, 0, 3);
831 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
832
833 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
834 glDrawArrays(GL_TRIANGLES, 0, 3);
835 EXPECT_GL_NO_ERROR();
836
837 glDeleteQueries(1, &query);
838 }
Martin Radevffe754b2017-07-31 10:38:07 +0300839}
840
Martin Radev8f276e22017-05-30 12:05:52 +0300841// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300842TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300843{
Jamie Madill3a256222018-12-08 09:56:39 -0500844 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
845
Martin Radev8f276e22017-05-30 12:05:52 +0300846 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
847 ASSERT_GL_NO_ERROR();
848
849 checkOutput();
850}
851
852// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300853TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300854{
Jamie Madill3a256222018-12-08 09:56:39 -0500855 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
856
Martin Radev8f276e22017-05-30 12:05:52 +0300857 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
858 ASSERT_GL_NO_ERROR();
859
860 checkOutput();
861}
862
863// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300864TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300865{
Jamie Madill3a256222018-12-08 09:56:39 -0500866 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
867
Martin Radev8f276e22017-05-30 12:05:52 +0300868 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
869 ASSERT_GL_NO_ERROR();
870
871 checkOutput();
872}
873
874// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300875TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300876{
Jamie Madill3a256222018-12-08 09:56:39 -0500877 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev8f276e22017-05-30 12:05:52 +0300878
Jamie Madill35cd7332018-12-02 12:03:33 -0500879 constexpr char kVS[] =
Martin Radev8f276e22017-05-30 12:05:52 +0300880 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700881 "#extension GL_OVR_multiview2 : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300882 "layout(num_views = 4) in;\n"
883 "in vec4 vPosition;\n"
884 "void main()\n"
885 "{\n"
886 " if (gl_ViewID_OVR == 0u) {\n"
887 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
888 " } else if (gl_ViewID_OVR == 1u) {\n"
889 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
890 " } else if (gl_ViewID_OVR == 2u) {\n"
891 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
892 " } else {\n"
893 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
894 " }"
895 " gl_Position.yzw = vPosition.yzw;\n"
896 "}\n";
897
Jamie Madill35cd7332018-12-02 12:03:33 -0500898 constexpr char kFS[] =
Martin Radev8f276e22017-05-30 12:05:52 +0300899 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700900 "#extension GL_OVR_multiview2 : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300901 "precision mediump float;\n"
902 "out vec4 col;\n"
903 "void main()\n"
904 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300905 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300906 "}\n";
907
Olli Etuaho4836acc2018-08-20 15:23:18 +0300908 updateFBOs(4, 1, 4);
Jamie Madill35cd7332018-12-02 12:03:33 -0500909 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev8f276e22017-05-30 12:05:52 +0300910
911 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
912 ASSERT_GL_NO_ERROR();
913
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300914 resolveMultisampledFBO();
Martin Radev8f276e22017-05-30 12:05:52 +0300915 for (int i = 0; i < 4; ++i)
916 {
917 for (int j = 0; j < 4; ++j)
918 {
Martin Radev8f276e22017-05-30 12:05:52 +0300919 if (i == j)
920 {
Martin Radev67a8a012017-09-08 13:03:52 +0300921 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300922 }
923 else
924 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300925 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300926 }
927 }
928 }
929 EXPECT_GL_NO_ERROR();
930}
931
932// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300933TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +0300934{
Jamie Madill3a256222018-12-08 09:56:39 -0500935 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev8f276e22017-05-30 12:05:52 +0300936
Jamie Madill35cd7332018-12-02 12:03:33 -0500937 constexpr char kVS[] =
Martin Radev8f276e22017-05-30 12:05:52 +0300938 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700939 "#extension GL_OVR_multiview2 : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300940 "layout(num_views = 2) in;\n"
941 "in vec4 vPosition;\n"
942 "void main()\n"
943 "{\n"
944 " vec4 p = vPosition;\n"
945 " if (gl_InstanceID == 1){\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300946 " p.y = p.y * 0.5 + 0.5;\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300947 " } else {\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300948 " p.y = p.y * 0.5 - 0.5;\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300949 " }\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300950 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x * 0.5 + 0.5 : p.x * 0.5 - 0.5);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300951 " gl_Position.yzw = p.yzw;\n"
952 "}\n";
953
Jamie Madill35cd7332018-12-02 12:03:33 -0500954 constexpr char kFS[] =
Martin Radev8f276e22017-05-30 12:05:52 +0300955 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700956 "#extension GL_OVR_multiview2 : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300957 "precision mediump float;\n"
958 "out vec4 col;\n"
959 "void main()\n"
960 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300961 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300962 "}\n";
963
Martin Radev3c25ad02017-08-22 17:36:53 +0300964 const int kViewWidth = 2;
965 const int kViewHeight = 2;
966 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300967 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Jamie Madill35cd7332018-12-02 12:03:33 -0500968 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev8f276e22017-05-30 12:05:52 +0300969
Martin Radev67a8a012017-09-08 13:03:52 +0300970 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 2u);
Martin Radev8f276e22017-05-30 12:05:52 +0300971 ASSERT_GL_NO_ERROR();
972
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300973 resolveMultisampledFBO();
974
Martin Radev67a8a012017-09-08 13:03:52 +0300975 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
976 {{255, 0}, {255, 0}}};
Martin Radev3c25ad02017-08-22 17:36:53 +0300977
978 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +0300979 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300980 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +0300981 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300982 for (int x = 0; x < 2; ++x)
983 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300984 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][y][x], 0,
985 expectedGreenChannel[view][y][x]),
Martin Radev3c25ad02017-08-22 17:36:53 +0300986 GetViewColor(x, y, view));
987 }
Martin Radev8f276e22017-05-30 12:05:52 +0300988 }
989 }
990}
991
Martin Radev553590a2017-07-31 16:40:39 +0300992// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
993// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
994// offset of each quad are passed as separate attributes which are indexed based on the
995// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
996// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
997// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
998// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +0300999TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +03001000{
Jamie Madill3a256222018-12-08 09:56:39 -05001001 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev553590a2017-07-31 16:40:39 +03001002
Corentin Wallez02cd1522018-08-22 13:46:21 +02001003 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001004 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001005 if (IsWindows() && IsD3D11())
1006 {
1007 ignoreD3D11SDKLayersWarnings();
1008 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001009
Jamie Madill35cd7332018-12-02 12:03:33 -05001010 constexpr char kVS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001011 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001012 "#extension GL_OVR_multiview2 : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001013 "layout(num_views = 2) in;\n"
1014 "in vec3 vPosition;\n"
1015 "in float offsetX;\n"
1016 "in float offsetY;\n"
1017 "void main()\n"
1018 "{\n"
1019 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001020 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001021 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
1022 " gl_Position.yzw = p.yzw;\n"
1023 "}\n";
1024
Jamie Madill35cd7332018-12-02 12:03:33 -05001025 constexpr char kFS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001026 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001027 "#extension GL_OVR_multiview2 : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001028 "precision mediump float;\n"
1029 "out vec4 col;\n"
1030 "void main()\n"
1031 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001032 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001033 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +03001034
1035 const int kViewWidth = 4;
1036 const int kViewHeight = 4;
1037 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001038 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Jamie Madill35cd7332018-12-02 12:03:33 -05001039 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev553590a2017-07-31 16:40:39 +03001040
1041 GLBuffer xOffsetVBO;
1042 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1043 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
1044 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
1045 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1046 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1047 glVertexAttribDivisor(xOffsetLoc, 3);
1048 glEnableVertexAttribArray(xOffsetLoc);
1049
1050 GLBuffer yOffsetVBO;
1051 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1052 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1053 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1054 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1055 glVertexAttribDivisor(yOffsetLoc, 1);
1056 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1057 glEnableVertexAttribArray(yOffsetLoc);
1058
Martin Radev67a8a012017-09-08 13:03:52 +03001059 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev553590a2017-07-31 16:40:39 +03001060 ASSERT_GL_NO_ERROR();
1061
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001062 resolveMultisampledFBO();
1063
Martin Radev67a8a012017-09-08 13:03:52 +03001064 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001065 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1066 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1067 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +03001068 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001069 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +03001070 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001071 for (int col = 0; col < 4; ++col)
1072 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001073 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0,
1074 expectedGreenChannel[view][row][col]),
Martin Radev3c25ad02017-08-22 17:36:53 +03001075 GetViewColor(col, row, view));
1076 }
Martin Radev553590a2017-07-31 16:40:39 +03001077 }
1078 }
1079}
1080
1081// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1082// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +03001083TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +03001084{
Jamie Madill3a256222018-12-08 09:56:39 -05001085 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev553590a2017-07-31 16:40:39 +03001086
Olli Etuaho4836acc2018-08-20 15:23:18 +03001087 updateFBOs(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +03001088
1089 // Create multiview program.
Jamie Madill35cd7332018-12-02 12:03:33 -05001090 constexpr char kVS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001091 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001092 "#extension GL_OVR_multiview2 : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001093 "layout(num_views = 2) in;\n"
1094 "layout(location = 0) in vec2 vPosition;\n"
1095 "layout(location = 1) in float offsetX;\n"
1096 "void main()\n"
1097 "{\n"
1098 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1099 " p.x += offsetX;\n"
1100 " gl_Position = p;\n"
1101 "}\n";
1102
Jamie Madill35cd7332018-12-02 12:03:33 -05001103 constexpr char kFS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001104 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001105 "#extension GL_OVR_multiview2 : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001106 "precision mediump float;\n"
1107 "out vec4 col;\n"
1108 "void main()\n"
1109 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001110 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001111 "}\n";
1112
Jamie Madill35cd7332018-12-02 12:03:33 -05001113 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev553590a2017-07-31 16:40:39 +03001114
Jamie Madill35cd7332018-12-02 12:03:33 -05001115 constexpr char kDummyVS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001116 "#version 300 es\n"
1117 "layout(location = 0) in vec2 vPosition;\n"
1118 "layout(location = 1) in float offsetX;\n"
1119 "void main()\n"
1120 "{\n"
1121 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1122 "}\n";
1123
Jamie Madill35cd7332018-12-02 12:03:33 -05001124 constexpr char kDummyFS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001125 "#version 300 es\n"
1126 "precision mediump float;\n"
1127 "out vec4 col;\n"
1128 "void main()\n"
1129 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001130 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001131 "}\n";
1132
Jamie Madill35cd7332018-12-02 12:03:33 -05001133 ANGLE_GL_PROGRAM(dummyProgram, kDummyVS, kDummyFS);
Martin Radev553590a2017-07-31 16:40:39 +03001134
1135 GLBuffer xOffsetVBO;
1136 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1137 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1138 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1139 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1140
1141 GLBuffer vertexVBO;
1142 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1143 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1144 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1145 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1146
1147 GLVertexArray vao[2];
1148 for (size_t i = 0u; i < 2u; ++i)
1149 {
1150 glBindVertexArray(vao[i]);
1151
1152 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1153 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1154 glEnableVertexAttribArray(0);
1155
1156 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1157 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1158 glEnableVertexAttribArray(1);
1159 }
1160 ASSERT_GL_NO_ERROR();
1161
1162 glViewport(0, 0, 1, 1);
1163 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001164 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001165 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001166
1167 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1168 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1169 // bits are cleared.
1170 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001171 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1172 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001173 glBindVertexArray(vao[0]);
1174 glVertexAttribDivisor(1, 0);
1175 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1176 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001177 ASSERT_GL_NO_ERROR();
1178
1179 // Check that vertexAttribDivisor uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001180 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001181 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001182 glUseProgram(program);
1183 glVertexAttribDivisor(1, 1);
1184 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001185
1186 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001187 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1188 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001189
1190 // Clear the buffers and propagate divisor to the driver.
1191 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1192 // dirty bits when useProgram is called.
1193 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001194 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1195 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001196 glVertexAttribDivisor(1, 1);
1197 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1198 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001199 ASSERT_GL_NO_ERROR();
1200
1201 // Check that useProgram uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001202 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001203 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001204 glUseProgram(program);
1205 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001206
1207 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001208 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1209 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001210
1211 // We go through similar steps as before.
1212 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001213 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1214 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001215 glVertexAttribDivisor(1, 1);
1216 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1217 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001218 ASSERT_GL_NO_ERROR();
1219
1220 // Check that bindVertexArray uses the number of views to update the divisor.
1221 {
1222 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1223 // divisor for vao[1] only.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001224 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001225 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001226 glBindVertexArray(vao[1]);
1227 glUseProgram(program);
1228 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001229 glBindVertexArray(0);
1230 ASSERT_GL_NO_ERROR();
1231 }
1232 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1233 // adjusts the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001234 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001235 glBindVertexArray(vao[0]);
1236 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001237
1238 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001239 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1240 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001241}
1242
Martin Radev0d671c92017-08-10 16:41:52 +03001243// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1244// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001245TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001246{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001247 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1248 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001249
Jamie Madill35cd7332018-12-02 12:03:33 -05001250 constexpr char kVS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001251 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001252 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001253 "layout(num_views = 2) in;\n"
1254 "in vec3 vPosition;\n"
1255 "void main()\n"
1256 "{\n"
1257 " gl_Position.x = 2.0;\n"
1258 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1259 "}\n";
1260
Jamie Madill35cd7332018-12-02 12:03:33 -05001261 constexpr char kFS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001262 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001263 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001264 "precision mediump float;\n"
1265 "out vec4 col;\n"
1266 "void main()\n"
1267 "{\n"
1268 " col = vec4(1,0,0,0);\n"
1269 "}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -05001270 ANGLE_GL_PROGRAM(program, kVS, kFS);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001271 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001272
1273 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1274 ASSERT_GL_NO_ERROR();
1275 EXPECT_GL_FALSE(result);
1276}
1277
1278// Test that there are fragments passing the occlusion query if only view 0 can produce
1279// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001280TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001281{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001282 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1283 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001284
Jamie Madill35cd7332018-12-02 12:03:33 -05001285 constexpr char kVS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001286 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001287 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001288 "layout(num_views = 2) in;\n"
1289 "in vec3 vPosition;\n"
1290 "void main()\n"
1291 "{\n"
1292 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1293 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1294 "}\n";
1295
Jamie Madill35cd7332018-12-02 12:03:33 -05001296 constexpr char kFS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001297 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001298 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001299 "precision mediump float;\n"
1300 "out vec4 col;\n"
1301 "void main()\n"
1302 "{\n"
1303 " col = vec4(1,0,0,0);\n"
1304 "}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -05001305 ANGLE_GL_PROGRAM(program, kVS, kFS);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001306 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001307
1308 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1309 ASSERT_GL_NO_ERROR();
1310 EXPECT_GL_TRUE(result);
1311}
1312
1313// Test that there are fragments passing the occlusion query if only view 1 can produce
1314// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001315TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001316{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001317 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1318 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001319
Jamie Madill35cd7332018-12-02 12:03:33 -05001320 constexpr char kVS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001321 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001322 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001323 "layout(num_views = 2) in;\n"
1324 "in vec3 vPosition;\n"
1325 "void main()\n"
1326 "{\n"
1327 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1328 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1329 "}\n";
1330
Jamie Madill35cd7332018-12-02 12:03:33 -05001331 constexpr char kFS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001332 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001333 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001334 "precision mediump float;\n"
1335 "out vec4 col;\n"
1336 "void main()\n"
1337 "{\n"
1338 " col = vec4(1,0,0,0);\n"
1339 "}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -05001340 ANGLE_GL_PROGRAM(program, kVS, kFS);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001341 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001342
1343 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1344 ASSERT_GL_NO_ERROR();
1345 EXPECT_GL_TRUE(result);
1346}
1347
Martin Radev41ac68e2017-06-06 12:16:58 +03001348// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1349// compiles and links without an error.
1350TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1351{
1352 if (!requestMultiviewExtension())
1353 {
1354 return;
1355 }
1356
Jamie Madill35cd7332018-12-02 12:03:33 -05001357 constexpr char kVS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001358 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001359 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001360 "layout(num_views = 2) in;\n"
1361 "void main()\n"
1362 "{\n"
1363 "}\n";
1364
Jamie Madill35cd7332018-12-02 12:03:33 -05001365 constexpr char kFS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001366 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001367 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001368 "precision mediump float;\n"
1369 "void main()\n"
1370 "{\n"
1371 "}\n";
1372
Jamie Madill35cd7332018-12-02 12:03:33 -05001373 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev41ac68e2017-06-06 12:16:58 +03001374 glUseProgram(program);
1375
1376 EXPECT_GL_NO_ERROR();
1377}
1378
1379// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1380// without an error.
1381TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1382{
1383 if (!requestMultiviewExtension())
1384 {
1385 return;
1386 }
1387
Jamie Madill35cd7332018-12-02 12:03:33 -05001388 constexpr char kVS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001389 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001390 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001391 "layout(num_views = 2) in;\n"
1392 "void main()\n"
1393 "{\n"
1394 " if (gl_ViewID_OVR == 0u) {\n"
1395 " gl_Position = vec4(1,0,0,1);\n"
1396 " } else {\n"
1397 " gl_Position = vec4(-1,0,0,1);\n"
1398 " }\n"
1399 "}\n";
1400
Jamie Madill35cd7332018-12-02 12:03:33 -05001401 constexpr char kFS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001402 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001403 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001404 "precision mediump float;\n"
1405 "void main()\n"
1406 "{\n"
1407 "}\n";
1408
Jamie Madill35cd7332018-12-02 12:03:33 -05001409 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev41ac68e2017-06-06 12:16:58 +03001410 glUseProgram(program);
1411
1412 EXPECT_GL_NO_ERROR();
1413}
1414
1415// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1416// without an error.
1417TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1418{
1419 if (!requestMultiviewExtension())
1420 {
1421 return;
1422 }
1423
Jamie Madill35cd7332018-12-02 12:03:33 -05001424 constexpr char kVS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001425 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001426 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001427 "layout(num_views = 2) in;\n"
1428 "void main()\n"
1429 "{\n"
1430 "}\n";
1431
Jamie Madill35cd7332018-12-02 12:03:33 -05001432 constexpr char kFS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001433 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001434 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001435 "precision mediump float;\n"
1436 "out vec4 col;\n"
1437 "void main()\n"
1438 "{\n"
1439 " if (gl_ViewID_OVR == 0u) {\n"
1440 " col = vec4(1,0,0,1);\n"
1441 " } else {\n"
1442 " col = vec4(-1,0,0,1);\n"
1443 " }\n"
1444 "}\n";
1445
Jamie Madill35cd7332018-12-02 12:03:33 -05001446 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev41ac68e2017-06-06 12:16:58 +03001447 glUseProgram(program);
1448
1449 EXPECT_GL_NO_ERROR();
1450}
1451
Martin Radev61bd9992017-08-11 13:10:55 +03001452// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001453TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001454{
1455 if (!requestMultiviewExtension())
1456 {
1457 return;
1458 }
1459
Geoff Lang25858162017-11-06 11:25:58 -05001460 // Test failing on P400 graphics card (anglebug.com/2228)
1461 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1462
Jamie Madill35cd7332018-12-02 12:03:33 -05001463 constexpr char kVS[] =
Martin Radev61bd9992017-08-11 13:10:55 +03001464 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001465 "#extension GL_OVR_multiview2 : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001466 "layout(num_views = 2) in;\n"
1467 "layout(location=0) in vec2 vPosition;\n"
1468 "void main()\n"
1469 "{\n"
1470 " gl_PointSize = 1.0;\n"
1471 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1472 "}\n";
1473
Jamie Madill35cd7332018-12-02 12:03:33 -05001474 constexpr char kFS[] =
Martin Radev61bd9992017-08-11 13:10:55 +03001475 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001476 "#extension GL_OVR_multiview2 : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001477 "precision mediump float;\n"
1478 "out vec4 col;\n"
1479 "void main()\n"
1480 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001481 " col = vec4(0,1,0,1);\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001482 "}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -05001483 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev61bd9992017-08-11 13:10:55 +03001484 glUseProgram(program);
1485
Martin Radev3c25ad02017-08-22 17:36:53 +03001486 const int kViewWidth = 4;
1487 const int kViewHeight = 2;
1488 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001489 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001490
1491 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1492 std::vector<Vector2> vertexDataInClipSpace =
1493 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1494 setupGeometry(vertexDataInClipSpace);
1495
1496 glDrawArrays(GL_POINTS, 0, 2);
1497
Martin Radev67a8a012017-09-08 13:03:52 +03001498 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001499 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001500 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001501}
1502
1503// The test checks that GL_LINES is correctly rendered.
1504// The behavior of this test is not guaranteed by the spec:
1505// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1506// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1507// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1508// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001509TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001510{
1511 if (!requestMultiviewExtension())
1512 {
1513 return;
1514 }
1515
Martin Radevced5c862017-08-17 16:05:29 +03001516 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001517 ASSERT_NE(program, 0u);
1518 glUseProgram(program);
1519 ASSERT_GL_NO_ERROR();
1520
Martin Radev3c25ad02017-08-22 17:36:53 +03001521 const int kViewWidth = 4;
1522 const int kViewHeight = 2;
1523 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001524 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001525
1526 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1527 std::vector<Vector2> vertexDataInClipSpace =
1528 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1529 setupGeometry(vertexDataInClipSpace);
1530
1531 glDrawArrays(GL_LINES, 0, 2);
1532
Martin Radev67a8a012017-09-08 13:03:52 +03001533 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001534 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001535 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001536
1537 glDeleteProgram(program);
1538}
1539
1540// The test checks that GL_LINE_STRIP is correctly rendered.
1541// The behavior of this test is not guaranteed by the spec:
1542// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1543// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1544// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1545// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001546TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001547{
1548 if (!requestMultiviewExtension())
1549 {
1550 return;
1551 }
1552
Martin Radevced5c862017-08-17 16:05:29 +03001553 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001554 ASSERT_NE(program, 0u);
1555 glUseProgram(program);
1556 ASSERT_GL_NO_ERROR();
1557
Martin Radev3c25ad02017-08-22 17:36:53 +03001558 const int kViewWidth = 4;
1559 const int kViewHeight = 2;
1560 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001561 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001562
1563 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1564 std::vector<Vector2> vertexDataInClipSpace =
1565 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1566 setupGeometry(vertexDataInClipSpace);
1567
1568 glDrawArrays(GL_LINE_STRIP, 0, 3);
1569
Martin Radev67a8a012017-09-08 13:03:52 +03001570 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001571 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001572 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001573
1574 glDeleteProgram(program);
1575}
1576
1577// The test checks that GL_LINE_LOOP is correctly rendered.
1578// The behavior of this test is not guaranteed by the spec:
1579// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1580// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1581// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1582// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001583TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001584{
1585 if (!requestMultiviewExtension())
1586 {
1587 return;
1588 }
1589
Martin Radevced5c862017-08-17 16:05:29 +03001590 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001591 ASSERT_NE(program, 0u);
1592 glUseProgram(program);
1593 ASSERT_GL_NO_ERROR();
1594
Martin Radev3c25ad02017-08-22 17:36:53 +03001595 const int kViewWidth = 4;
1596 const int kViewHeight = 4;
1597 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001598 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001599
1600 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1601 Vector2I(0, 3)};
1602 std::vector<Vector2> vertexDataInClipSpace =
1603 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1604 setupGeometry(vertexDataInClipSpace);
1605
1606 glDrawArrays(GL_LINE_LOOP, 0, 4);
1607
Martin Radev67a8a012017-09-08 13:03:52 +03001608 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001609 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1610 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001611 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001612
1613 glDeleteProgram(program);
1614}
1615
1616// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001617TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001618{
1619 if (!requestMultiviewExtension())
1620 {
1621 return;
1622 }
1623
Martin Radevced5c862017-08-17 16:05:29 +03001624 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001625 ASSERT_NE(program, 0u);
1626 glUseProgram(program);
1627 ASSERT_GL_NO_ERROR();
1628
1629 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1630 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1631 setupGeometry(vertexDataInClipSpace);
1632
Martin Radev3c25ad02017-08-22 17:36:53 +03001633 const int kViewWidth = 2;
1634 const int kViewHeight = 2;
1635 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001636 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001637
1638 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1639
Martin Radev67a8a012017-09-08 13:03:52 +03001640 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1641 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1642 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001643
1644 glDeleteProgram(program);
1645}
1646
1647// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001648TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001649{
1650 if (!requestMultiviewExtension())
1651 {
1652 return;
1653 }
1654
Martin Radevced5c862017-08-17 16:05:29 +03001655 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001656 ASSERT_NE(program, 0u);
1657 glUseProgram(program);
1658 ASSERT_GL_NO_ERROR();
1659
1660 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1661 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1662 setupGeometry(vertexDataInClipSpace);
1663
Martin Radev3c25ad02017-08-22 17:36:53 +03001664 const int kViewWidth = 2;
1665 const int kViewHeight = 2;
1666 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001667 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001668
1669 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1670
Martin Radev67a8a012017-09-08 13:03:52 +03001671 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1672 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1673 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001674
1675 glDeleteProgram(program);
1676}
1677
Martin Radev0abb7a22017-08-28 15:34:45 +03001678// Verify that re-linking a program adjusts the attribute divisor.
1679// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1680// to each other. The quads' position and color depend on the corresponding attribute divisors.
1681TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1682{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001683 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev0abb7a22017-08-28 15:34:45 +03001684 {
1685 return;
1686 }
1687
Corentin Wallez02cd1522018-08-22 13:46:21 +02001688 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001689 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001690 if (IsWindows() && IsD3D11())
1691 {
1692 ignoreD3D11SDKLayersWarnings();
1693 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001694
Martin Radev0abb7a22017-08-28 15:34:45 +03001695 const int kViewWidth = 4;
1696 const int kViewHeight = 1;
1697 const int kNumViews = 2;
1698
Jamie Madill35cd7332018-12-02 12:03:33 -05001699 constexpr char kFS[] =
Martin Radev0abb7a22017-08-28 15:34:45 +03001700 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001701 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001702 "precision mediump float;\n"
1703 "in vec4 oColor;\n"
1704 "out vec4 col;\n"
1705 "void main()\n"
1706 "{\n"
1707 " col = oColor;\n"
1708 "}\n";
1709
1710 auto generateVertexShaderSource = [](int numViews) -> std::string {
1711 std::string source =
1712 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001713 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001714 "layout(num_views = " +
1715 ToString(numViews) +
1716 ") in;\n"
1717 "in vec3 vPosition;\n"
1718 "in float vOffsetX;\n"
1719 "in vec4 vColor;\n"
1720 "out vec4 oColor;\n"
1721 "void main()\n"
1722 "{\n"
1723 " vec4 p = vec4(vPosition, 1.);\n"
1724 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1725 " oColor = vColor;\n"
1726 " gl_Position = p;\n"
1727 "}\n";
1728 return source;
1729 };
1730
1731 std::string vsSource = generateVertexShaderSource(kNumViews);
Jamie Madill35cd7332018-12-02 12:03:33 -05001732 ANGLE_GL_PROGRAM(program, vsSource.c_str(), kFS);
Martin Radev0abb7a22017-08-28 15:34:45 +03001733 glUseProgram(program);
1734
1735 GLint positionLoc;
1736 GLBuffer xOffsetVBO;
1737 GLint xOffsetLoc;
1738 GLBuffer colorVBO;
1739 GLint colorLoc;
1740
1741 {
1742 // Initialize buffers and setup attributes.
1743 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1744 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1745 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1746 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1747 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1748 glVertexAttribDivisor(xOffsetLoc, 1);
1749 glEnableVertexAttribArray(xOffsetLoc);
1750
1751 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1752 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1753 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1754 colorLoc = glGetAttribLocation(program, "vColor");
1755 glVertexAttribDivisor(colorLoc, 2);
1756 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1757 glEnableVertexAttribArray(colorLoc);
1758
1759 positionLoc = glGetAttribLocation(program, "vPosition");
1760 }
1761
1762 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001763 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001764
Martin Radev67a8a012017-09-08 13:03:52 +03001765 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001766 ASSERT_GL_NO_ERROR();
1767
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001768 resolveMultisampledFBO();
Martin Radev0abb7a22017-08-28 15:34:45 +03001769 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1770 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1771 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1772 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1773 }
1774
1775 {
1776 const int kNewNumViews = 3;
1777 vsSource = generateVertexShaderSource(kNewNumViews);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001778 updateFBOs(kViewWidth, kViewHeight, kNewNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001779
Jamie Madill35cd7332018-12-02 12:03:33 -05001780 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource.c_str());
Martin Radev0abb7a22017-08-28 15:34:45 +03001781 ASSERT_NE(0u, vs);
Jamie Madill35cd7332018-12-02 12:03:33 -05001782 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
Martin Radev0abb7a22017-08-28 15:34:45 +03001783 ASSERT_NE(0u, fs);
1784
1785 GLint numAttachedShaders = 0;
1786 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1787
1788 GLuint attachedShaders[2] = {0u};
1789 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1790 for (int i = 0; i < 2; ++i)
1791 {
1792 glDetachShader(program, attachedShaders[i]);
1793 }
1794
1795 glAttachShader(program, vs);
1796 glDeleteShader(vs);
1797
1798 glAttachShader(program, fs);
1799 glDeleteShader(fs);
1800
1801 glBindAttribLocation(program, positionLoc, "vPosition");
1802 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1803 glBindAttribLocation(program, colorLoc, "vColor");
1804
1805 glLinkProgram(program);
1806
Martin Radev67a8a012017-09-08 13:03:52 +03001807 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001808 ASSERT_GL_NO_ERROR();
1809
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001810 resolveMultisampledFBO();
Martin Radev0abb7a22017-08-28 15:34:45 +03001811 for (int i = 0; i < kNewNumViews; ++i)
1812 {
1813 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1814 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1815 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1816 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1817 }
1818 }
1819}
1820
Martin Radevced5c862017-08-17 16:05:29 +03001821// Test that useProgram applies the number of views in computing the final value of the attribute
1822// divisor.
1823TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1824{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001825 if (!requestMultiviewExtension(isMultisampled()))
Martin Radevced5c862017-08-17 16:05:29 +03001826 {
1827 return;
1828 }
1829
Geoff Lang25858162017-11-06 11:25:58 -05001830 // Test failing on P400 graphics card (anglebug.com/2228)
1831 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1832
Olli Etuaho44ae8992018-08-20 15:37:09 +03001833 // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
1834 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001835 if (IsWindows() && IsD3D11())
1836 {
1837 ignoreD3D11SDKLayersWarnings();
1838 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001839
Martin Radevced5c862017-08-17 16:05:29 +03001840 GLVertexArray vao;
1841 glBindVertexArray(vao);
1842 GLBuffer vbo;
1843 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1844 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
1845 Vector2I(3, 0)};
1846 std::vector<Vector2> vertexDataInClipSpace =
1847 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
1848 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
1849 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
1850 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1851 glEnableVertexAttribArray(0);
1852 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
1853 glVertexAttribDivisor(0, 1);
1854 ASSERT_GL_NO_ERROR();
1855
1856 // Create a program and fbo with N views and draw N instances of a point horizontally.
1857 for (int numViews = 2; numViews <= 4; ++numViews)
1858 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001859 updateFBOs(4, 1, numViews);
Martin Radevced5c862017-08-17 16:05:29 +03001860 ASSERT_GL_NO_ERROR();
1861
1862 GLuint program = CreateSimplePassthroughProgram(numViews);
1863 ASSERT_NE(program, 0u);
1864 glUseProgram(program);
1865 ASSERT_GL_NO_ERROR();
1866
1867 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
1868
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001869 resolveMultisampledFBO();
Martin Radevced5c862017-08-17 16:05:29 +03001870 for (int view = 0; view < numViews; ++view)
1871 {
1872 for (int j = 0; j < numViews; ++j)
1873 {
Martin Radev67a8a012017-09-08 13:03:52 +03001874 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03001875 }
1876 for (int j = numViews; j < 4; ++j)
1877 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001878 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03001879 }
1880 }
1881
1882 glDeleteProgram(program);
1883 }
1884}
1885
Martin Radev72b4e1e2017-08-31 15:42:56 +03001886// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
1887TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
1888{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001889 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev72b4e1e2017-08-31 15:42:56 +03001890 {
1891 return;
1892 }
1893
Jamie Madill35cd7332018-12-02 12:03:33 -05001894 constexpr char kVS[] =
Martin Radev72b4e1e2017-08-31 15:42:56 +03001895 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001896 "#extension GL_OVR_multiview2 : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001897 "layout(num_views = 3) in;\n"
1898 "in vec3 vPosition;\n"
1899 "void main()\n"
1900 "{\n"
1901 " gl_Position = vec4(vPosition, 1.);\n"
1902 "}\n";
1903
Jamie Madill35cd7332018-12-02 12:03:33 -05001904 constexpr char kFS[] =
Martin Radev72b4e1e2017-08-31 15:42:56 +03001905 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001906 "#extension GL_OVR_multiview2 : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001907 "precision mediump float;\n"
1908 "out vec4 col;\n"
1909 "void main()\n"
1910 "{\n"
1911 " if (gl_ViewID_OVR == 0u) {\n"
1912 " col = vec4(1,0,0,1);\n"
1913 " } else if (gl_ViewID_OVR == 1u) {\n"
1914 " col = vec4(0,1,0,1);\n"
1915 " } else if (gl_ViewID_OVR == 2u) {\n"
1916 " col = vec4(0,0,1,1);\n"
1917 " } else {\n"
1918 " col = vec4(0,0,0,0);\n"
1919 " }\n"
1920 "}\n";
1921
Olli Etuaho4836acc2018-08-20 15:23:18 +03001922 updateFBOs(1, 1, 3);
Jamie Madill35cd7332018-12-02 12:03:33 -05001923 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev72b4e1e2017-08-31 15:42:56 +03001924
1925 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1926 ASSERT_GL_NO_ERROR();
1927
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001928 resolveMultisampledFBO();
Martin Radev72b4e1e2017-08-31 15:42:56 +03001929 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1930 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1931 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
1932}
1933
1934// The test checks that the inactive layers of a 2D texture array are not written to by a
1935// multi-view program.
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001936TEST_P(MultiviewLayeredRenderTest, RenderToSubrangeOfLayers)
Martin Radev72b4e1e2017-08-31 15:42:56 +03001937{
1938 if (!requestMultiviewExtension())
1939 {
1940 return;
1941 }
1942
Jamie Madill35cd7332018-12-02 12:03:33 -05001943 constexpr char kVS[] =
Martin Radev72b4e1e2017-08-31 15:42:56 +03001944 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001945 "#extension GL_OVR_multiview2 : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001946 "layout(num_views = 2) in;\n"
1947 "in vec3 vPosition;\n"
1948 "void main()\n"
1949 "{\n"
1950 " gl_Position = vec4(vPosition, 1.);\n"
1951 "}\n";
1952
Jamie Madill35cd7332018-12-02 12:03:33 -05001953 constexpr char kFS[] =
Martin Radev72b4e1e2017-08-31 15:42:56 +03001954 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001955 "#extension GL_OVR_multiview2 : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001956 "precision mediump float;\n"
1957 "out vec4 col;\n"
1958 "void main()\n"
1959 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001960 " col = vec4(0,1,0,1);\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001961 "}\n";
1962
Olli Etuaho4836acc2018-08-20 15:23:18 +03001963 updateFBOs(1, 1, 2, 4, 1);
Jamie Madill35cd7332018-12-02 12:03:33 -05001964 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev72b4e1e2017-08-31 15:42:56 +03001965
1966 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1967 ASSERT_GL_NO_ERROR();
1968
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001969 resolveMultisampledFBO();
Martin Radev72b4e1e2017-08-31 15:42:56 +03001970 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +03001971 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1972 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03001973 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
1974}
1975
Martin Radevc1d4e552017-08-21 12:01:10 +03001976// The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
1977// potential bugs if the view is selected in the VS. The test contains a program in which the
1978// gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
1979// fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
1980// never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
1981// green for view 1.
1982TEST_P(MultiviewRenderTest, FlatInterpolation)
Martin Radev3c25ad02017-08-22 17:36:53 +03001983{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001984 if (!requestMultiviewExtension(isMultisampled()))
Martin Radevc1d4e552017-08-21 12:01:10 +03001985 {
1986 return;
1987 }
1988
Jamie Madill35cd7332018-12-02 12:03:33 -05001989 constexpr char kVS[] =
Martin Radevc1d4e552017-08-21 12:01:10 +03001990 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001991 "#extension GL_OVR_multiview2 : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03001992 "layout(num_views = 2) in;\n"
1993 "in vec3 vPosition;\n"
1994 "flat out int oInstanceID;\n"
1995 "void main()\n"
1996 "{\n"
1997 " gl_Position = vec4(vPosition, 1.);\n"
1998 " oInstanceID = gl_InstanceID;\n"
1999 "}\n";
2000
Jamie Madill35cd7332018-12-02 12:03:33 -05002001 constexpr char kFS[] =
Martin Radevc1d4e552017-08-21 12:01:10 +03002002 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07002003 "#extension GL_OVR_multiview2 : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002004 "precision mediump float;\n"
2005 "flat in int oInstanceID;\n"
2006 "out vec4 col;\n"
2007 "void main()\n"
2008 "{\n"
2009 " if (oInstanceID < 0) {\n"
2010 " discard;\n"
2011 " }\n"
2012 " if (gl_ViewID_OVR == 0u) {\n"
2013 " col = vec4(1,0,0,1);\n"
2014 " } else {\n"
2015 " col = vec4(0,1,0,1);\n"
2016 " }\n"
2017 "}\n";
2018
Olli Etuaho4836acc2018-08-20 15:23:18 +03002019 updateFBOs(1, 1, 2);
Jamie Madill35cd7332018-12-02 12:03:33 -05002020 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radevc1d4e552017-08-21 12:01:10 +03002021
2022 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2023 ASSERT_GL_NO_ERROR();
2024
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002025 resolveMultisampledFBO();
Martin Radevc1d4e552017-08-21 12:01:10 +03002026 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2027 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +03002028}
2029
Olli Etuaho604d8732018-07-20 11:02:43 +03002030// This test assigns gl_ViewID_OVR to a flat int varying and then sets the color based on that
2031// varying in the fragment shader.
2032TEST_P(MultiviewRenderTest, FlatInterpolation2)
2033{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002034 if (!requestMultiviewExtension(isMultisampled()))
Olli Etuaho604d8732018-07-20 11:02:43 +03002035 {
2036 return;
2037 }
2038
Jamie Madill35cd7332018-12-02 12:03:33 -05002039 constexpr char kVS[] =
Olli Etuaho604d8732018-07-20 11:02:43 +03002040 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07002041 "#extension GL_OVR_multiview2 : require\n"
Olli Etuaho604d8732018-07-20 11:02:43 +03002042 "layout(num_views = 2) in;\n"
2043 "in vec3 vPosition;\n"
2044 "flat out int flatVarying;\n"
2045 "void main()\n"
2046 "{\n"
2047 " gl_Position = vec4(vPosition, 1.);\n"
2048 " flatVarying = int(gl_ViewID_OVR);\n"
2049 "}\n";
2050
Jamie Madill35cd7332018-12-02 12:03:33 -05002051 constexpr char kFS[] =
Olli Etuaho604d8732018-07-20 11:02:43 +03002052 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07002053 "#extension GL_OVR_multiview2 : require\n"
Olli Etuaho604d8732018-07-20 11:02:43 +03002054 "precision mediump float;\n"
2055 "flat in int flatVarying;\n"
2056 "out vec4 col;\n"
2057 "void main()\n"
2058 "{\n"
2059 " if (flatVarying == 0) {\n"
2060 " col = vec4(1,0,0,1);\n"
2061 " } else {\n"
2062 " col = vec4(0,1,0,1);\n"
2063 " }\n"
2064 "}\n";
2065
Olli Etuaho4836acc2018-08-20 15:23:18 +03002066 updateFBOs(1, 1, 2);
Jamie Madill35cd7332018-12-02 12:03:33 -05002067 ANGLE_GL_PROGRAM(program, kVS, kFS);
Olli Etuaho604d8732018-07-20 11:02:43 +03002068
2069 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2070 ASSERT_GL_NO_ERROR();
2071
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002072 resolveMultisampledFBO();
Olli Etuaho604d8732018-07-20 11:02:43 +03002073 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2074 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2075}
2076
Mingyu Hu7d64c482019-03-12 14:27:40 -07002077MultiviewRenderTestParams VertexShaderOpenGL()
Martin Radev265a6d42017-09-12 16:51:37 +03002078{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002079 return MultiviewRenderTestParams(0, VertexShaderOpenGL(3, 0));
Martin Radev265a6d42017-09-12 16:51:37 +03002080}
2081
Mingyu Hu7d64c482019-03-12 14:27:40 -07002082MultiviewRenderTestParams GeomShaderD3D11()
Martin Radev3c25ad02017-08-22 17:36:53 +03002083{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002084 return MultiviewRenderTestParams(0, GeomShaderD3D11(3, 0));
Martin Radev3c25ad02017-08-22 17:36:53 +03002085}
2086
Mingyu Hu7d64c482019-03-12 14:27:40 -07002087MultiviewRenderTestParams VertexShaderD3D11()
Martin Radev3c25ad02017-08-22 17:36:53 +03002088{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002089 return MultiviewRenderTestParams(0, VertexShaderD3D11(3, 0));
Martin Radev3c25ad02017-08-22 17:36:53 +03002090}
2091
Mingyu Hu7d64c482019-03-12 14:27:40 -07002092MultiviewRenderTestParams MultisampledVertexShaderOpenGL()
Martin Radev72b4e1e2017-08-31 15:42:56 +03002093{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002094 return MultiviewRenderTestParams(2, VertexShaderOpenGL(3, 1));
Martin Radevc1d4e552017-08-21 12:01:10 +03002095}
2096
Mingyu Hu7d64c482019-03-12 14:27:40 -07002097MultiviewRenderTestParams MultisampledVertexShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002098{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002099 return MultiviewRenderTestParams(2, VertexShaderD3D11(3, 1));
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002100}
2101
Jamie Madill04c084d2018-08-08 15:49:28 -04002102ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest,
Olli Etuaho44ae8992018-08-20 15:37:09 +03002103 VertexShaderOpenGL(3, 1),
2104 VertexShaderD3D11(3, 1));
Martin Radevced5c862017-08-17 16:05:29 +03002105ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
Mingyu Hu7d64c482019-03-12 14:27:40 -07002106 VertexShaderOpenGL(),
2107 MultisampledVertexShaderOpenGL(),
2108 GeomShaderD3D11(),
2109 VertexShaderD3D11(),
2110 MultisampledVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002111ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
Mingyu Hu7d64c482019-03-12 14:27:40 -07002112 VertexShaderOpenGL(),
2113 MultisampledVertexShaderOpenGL(),
2114 GeomShaderD3D11(),
2115 VertexShaderD3D11(),
2116 MultisampledVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002117ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
Mingyu Hu7d64c482019-03-12 14:27:40 -07002118 VertexShaderOpenGL(),
2119 GeomShaderD3D11(),
2120 VertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002121ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
Olli Etuaho4bcaf992018-08-17 17:18:28 +03002122 VertexShaderOpenGL(3, 0),
2123 GeomShaderD3D11(3, 0),
2124 VertexShaderD3D11(3, 0));
Martin Radevced5c862017-08-17 16:05:29 +03002125ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
Mingyu Hu7d64c482019-03-12 14:27:40 -07002126 VertexShaderOpenGL(),
2127 GeomShaderD3D11(),
2128 VertexShaderD3D11());
Jamie Madill04c084d2018-08-08 15:49:28 -04002129ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, VertexShaderOpenGL(3, 0), GeomShaderD3D11(3, 0));