blob: 003cea33ba48ff897123026603ae6c52738a0b19 [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) {}
Olli Etuaho4836acc2018-08-20 15:23:18 +0300244 void SetUp() override { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300245 void TearDown() override { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
Martin Radevc1d4e552017-08-21 12:01:10 +0300246
247 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
248 {
249 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
250 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300251};
252
Jamie Madill04c084d2018-08-08 15:49:28 -0400253constexpr char kDualViewVSSource[] = R"(#version 300 es
Mingyu Hu7d64c482019-03-12 14:27:40 -0700254#extension GL_OVR_multiview2 : require
Jamie Madill04c084d2018-08-08 15:49:28 -0400255layout(num_views = 2) in;
256in vec4 vPosition;
257void main()
258{
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300259 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 -0400260 gl_Position.yzw = vPosition.yzw;
261})";
262
263constexpr char kDualViewFSSource[] = R"(#version 300 es
Mingyu Hu7d64c482019-03-12 14:27:40 -0700264#extension GL_OVR_multiview2 : require
Jamie Madill04c084d2018-08-08 15:49:28 -0400265precision mediump float;
266out vec4 col;
267void main()
268{
269 col = vec4(0,1,0,1);
270})";
271
Martin Radev3c25ad02017-08-22 17:36:53 +0300272class MultiviewRenderDualViewTest : public MultiviewRenderTest
273{
274 protected:
275 MultiviewRenderDualViewTest() : mProgram(0u) {}
Martin Radev8f276e22017-05-30 12:05:52 +0300276
277 void SetUp() override
278 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300279 MultiviewRenderTest::SetUp();
Martin Radev8f276e22017-05-30 12:05:52 +0300280
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300281 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +0300282 {
283 return;
284 }
285
Olli Etuaho4836acc2018-08-20 15:23:18 +0300286 updateFBOs(2, 1, 2);
Jamie Madill04c084d2018-08-08 15:49:28 -0400287 mProgram = CompileProgram(kDualViewVSSource, kDualViewFSSource);
Martin Radev61bd9992017-08-11 13:10:55 +0300288 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300289 glUseProgram(mProgram);
290 ASSERT_GL_NO_ERROR();
291 }
292
Olli Etuaho44ae8992018-08-20 15:37:09 +0300293 void TearDown() override
294 {
295 if (mProgram != 0u)
296 {
297 glDeleteProgram(mProgram);
298 mProgram = 0u;
299 }
300
301 MultiviewRenderTest::TearDown();
302 }
303
Martin Radev8f276e22017-05-30 12:05:52 +0300304 void checkOutput()
305 {
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300306 resolveMultisampledFBO();
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300307 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +0300308 EXPECT_EQ(GLColor::green, GetViewColor(1, 0, 0));
309 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300310 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(1, 0, 1));
Martin Radev8f276e22017-05-30 12:05:52 +0300311 }
312
313 GLuint mProgram;
314};
315
Olli Etuaho44ae8992018-08-20 15:37:09 +0300316// Base class for tests that care mostly about draw call validity and not rendering results.
317class MultiviewDrawValidationTest : public MultiviewTest
Jamie Madill04c084d2018-08-08 15:49:28 -0400318{
319 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300320 MultiviewDrawValidationTest() : MultiviewTest() {}
Jamie Madill04c084d2018-08-08 15:49:28 -0400321
Mingyu Hu7d64c482019-03-12 14:27:40 -0700322 void initOnePixelColorTexture2DSingleLayered(GLuint texId)
Jamie Madill04c084d2018-08-08 15:49:28 -0400323 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700324 glBindTexture(GL_TEXTURE_2D_ARRAY, texId);
325 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
326 nullptr);
327 }
328
329 void initOnePixelColorTexture2DMultiLayered(GLuint texId)
330 {
331 glBindTexture(GL_TEXTURE_2D_ARRAY, texId);
332 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
333 nullptr);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300334 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400335
Olli Etuaho44ae8992018-08-20 15:37:09 +0300336 // This initializes a simple VAO with a valid vertex buffer and index buffer with three
337 // vertices.
338 void initVAO(GLuint vao, GLuint vertexBuffer, GLuint indexBuffer)
339 {
340 glBindVertexArray(vao);
Jamie Madill04c084d2018-08-08 15:49:28 -0400341
342 const float kVertexData[3] = {0.0f};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300343 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400344 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
345
346 const unsigned int kIndices[3] = {0u, 1u, 2u};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300347 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400348 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
349 GL_STATIC_DRAW);
350 ASSERT_GL_NO_ERROR();
351 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400352};
353
Martin Radev3c25ad02017-08-22 17:36:53 +0300354class MultiviewOcclusionQueryTest : public MultiviewRenderTest
Martin Radev0d671c92017-08-10 16:41:52 +0300355{
356 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300357 MultiviewOcclusionQueryTest() {}
Martin Radev0d671c92017-08-10 16:41:52 +0300358
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400359 bool requestOcclusionQueryExtension()
360 {
Jamie Madillb8149072019-04-30 16:14:44 -0400361 if (IsGLExtensionRequestable("GL_EXT_occlusion_query_boolean"))
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400362 {
363 glRequestExtensionANGLE("GL_EXT_occlusion_query_boolean");
364 }
365
Jamie Madillb8149072019-04-30 16:14:44 -0400366 if (!IsGLExtensionEnabled("GL_EXT_occlusion_query_boolean"))
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400367 {
368 std::cout << "Test skipped due to missing GL_EXT_occlusion_query_boolean." << std::endl;
369 return false;
370 }
371 return true;
372 }
373
Martin Radev0d671c92017-08-10 16:41:52 +0300374 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
375 {
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400376 GLQueryEXT query;
377 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED, query);
Martin Radev0d671c92017-08-10 16:41:52 +0300378 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
379 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
380
381 GLuint result = GL_TRUE;
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400382 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT, &result);
Martin Radev0d671c92017-08-10 16:41:52 +0300383 return result;
384 }
385};
386
Olli Etuaho4bcaf992018-08-17 17:18:28 +0300387class MultiviewProgramGenerationTest : public MultiviewTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300388{
389 protected:
390 MultiviewProgramGenerationTest() {}
391};
392
Martin Radev3c25ad02017-08-22 17:36:53 +0300393class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300394{
395 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300396 MultiviewRenderPrimitiveTest() : mVBO(0u) {}
397
398 void SetUp() override
399 {
400 MultiviewRenderTest::SetUp();
401 glGenBuffers(1, &mVBO);
402 }
403
404 void TearDown() override
405 {
406 if (mVBO)
407 {
408 glDeleteBuffers(1, &mVBO);
409 mVBO = 0u;
410 }
411 MultiviewRenderTest::TearDown();
412 }
Martin Radev61bd9992017-08-11 13:10:55 +0300413
414 void setupGeometry(const std::vector<Vector2> &vertexData)
415 {
Martin Radev61bd9992017-08-11 13:10:55 +0300416 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
417 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
418 GL_STATIC_DRAW);
419 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500420 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +0300421 }
422
Martin Radev67a8a012017-09-08 13:03:52 +0300423 void checkGreenChannel(const GLubyte expectedGreenChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300424 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300425 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300426 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300427 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300428 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300429 for (int h = 0; h < mViewHeight; ++h)
430 {
431 size_t flatIndex =
432 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300433 EXPECT_EQ(GLColor(0, expectedGreenChannelData[flatIndex], 0,
434 expectedGreenChannelData[flatIndex]),
Martin Radev3c25ad02017-08-22 17:36:53 +0300435 GetViewColor(w, h, view));
436 }
Martin Radev61bd9992017-08-11 13:10:55 +0300437 }
438 }
439 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300440 GLuint mVBO;
Martin Radev61bd9992017-08-11 13:10:55 +0300441};
442
Olli Etuaho4836acc2018-08-20 15:23:18 +0300443class MultiviewLayeredRenderTest : public MultiviewFramebufferTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300444 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev72b4e1e2017-08-31 15:42:56 +0300445{
446 protected:
Mingyu Hu7d64c482019-03-12 14:27:40 -0700447 MultiviewLayeredRenderTest() : MultiviewFramebufferTestBase(GetParam(), 0) {}
Olli Etuaho44ae8992018-08-20 15:37:09 +0300448 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
449 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
450 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
Martin Radevc1d4e552017-08-21 12:01:10 +0300451 {
452 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
453 }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300454};
455
Mingyu Hu7d64c482019-03-12 14:27:40 -0700456// The test verifies that glDraw*Indirect works for any number of views.
Martin Radev7cf61662017-07-26 17:10:53 +0300457TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300458{
Jamie Madill3a256222018-12-08 09:56:39 -0500459 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radev14a26ae2017-07-24 15:56:29 +0300460
Jamie Madill35cd7332018-12-02 12:03:33 -0500461 constexpr char kFS[] =
Martin Radev14a26ae2017-07-24 15:56:29 +0300462 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700463 "#extension GL_OVR_multiview2 : require\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300464 "precision mediump float;\n"
shrekshao15ce8222019-03-18 19:25:21 -0700465 "out vec4 color;\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300466 "void main()\n"
shrekshao15ce8222019-03-18 19:25:21 -0700467 "{color = vec4(1);}\n";
Martin Radev14a26ae2017-07-24 15:56:29 +0300468
Olli Etuaho44ae8992018-08-20 15:37:09 +0300469 GLVertexArray vao;
470 GLBuffer vertexBuffer;
471 GLBuffer indexBuffer;
472 initVAO(vao, vertexBuffer, indexBuffer);
473
474 GLFramebuffer fbo;
475 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
476
Martin Radev14a26ae2017-07-24 15:56:29 +0300477 GLBuffer commandBuffer;
478 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
479 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
480 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
481 ASSERT_GL_NO_ERROR();
482
Mingyu Hu7d64c482019-03-12 14:27:40 -0700483 // Check that no errors are generated with the framebuffer having 2 views.
Martin Radev14a26ae2017-07-24 15:56:29 +0300484 {
Jamie Madill35cd7332018-12-02 12:03:33 -0500485 constexpr char kVS[] =
Martin Radev14a26ae2017-07-24 15:56:29 +0300486 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700487 "#extension GL_OVR_multiview2 : require\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300488 "layout(num_views = 2) in;\n"
489 "void main()\n"
490 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500491 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev14a26ae2017-07-24 15:56:29 +0300492 glUseProgram(program);
493
Mingyu Hu7d64c482019-03-12 14:27:40 -0700494 GLTexture tex2DArray;
495 initOnePixelColorTexture2DMultiLayered(tex2DArray);
496
497 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radev14a26ae2017-07-24 15:56:29 +0300498
499 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700500 EXPECT_GL_NO_ERROR();
Martin Radev14a26ae2017-07-24 15:56:29 +0300501
502 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700503 EXPECT_GL_NO_ERROR();
Martin Radev14a26ae2017-07-24 15:56:29 +0300504 }
505
506 // Check that no errors are generated if the number of views is 1.
507 {
Jamie Madill35cd7332018-12-02 12:03:33 -0500508 constexpr char kVS[] =
Martin Radev14a26ae2017-07-24 15:56:29 +0300509 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700510 "#extension GL_OVR_multiview2 : require\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300511 "layout(num_views = 1) in;\n"
512 "void main()\n"
513 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500514 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev14a26ae2017-07-24 15:56:29 +0300515 glUseProgram(program);
516
Mingyu Hu7d64c482019-03-12 14:27:40 -0700517 GLTexture tex2D;
518 initOnePixelColorTexture2DSingleLayered(tex2D);
519
520 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Martin Radev14a26ae2017-07-24 15:56:29 +0300521
522 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
523 EXPECT_GL_NO_ERROR();
524
525 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
526 EXPECT_GL_NO_ERROR();
527 }
528}
529
Martin Radev7cf61662017-07-26 17:10:53 +0300530// The test verifies that glDraw*:
531// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
532// program differs.
533// 2) does not generate any error if the number of views is the same.
Martin Radev7cf61662017-07-26 17:10:53 +0300534TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
535{
Jamie Madill3a256222018-12-08 09:56:39 -0500536 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radev7cf61662017-07-26 17:10:53 +0300537
Jamie Madill35cd7332018-12-02 12:03:33 -0500538 constexpr char kVS[] =
Martin Radev7cf61662017-07-26 17:10:53 +0300539 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700540 "#extension GL_OVR_multiview2 : require\n"
Martin Radev7cf61662017-07-26 17:10:53 +0300541 "layout(num_views = 2) in;\n"
542 "void main()\n"
543 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500544 constexpr char kFS[] =
Martin Radev7cf61662017-07-26 17:10:53 +0300545 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700546 "#extension GL_OVR_multiview2 : require\n"
Martin Radev7cf61662017-07-26 17:10:53 +0300547 "precision mediump float;\n"
shrekshao15ce8222019-03-18 19:25:21 -0700548 "out vec4 color;\n"
Martin Radev7cf61662017-07-26 17:10:53 +0300549 "void main()\n"
shrekshao15ce8222019-03-18 19:25:21 -0700550 "{color = vec4(1);}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500551 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev7cf61662017-07-26 17:10:53 +0300552 glUseProgram(program);
553
Olli Etuaho44ae8992018-08-20 15:37:09 +0300554 GLVertexArray vao;
555 GLBuffer vertexBuffer;
556 GLBuffer indexBuffer;
557 initVAO(vao, vertexBuffer, indexBuffer);
558
559 GLFramebuffer fbo;
560 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
561
Martin Radev7cf61662017-07-26 17:10:53 +0300562 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
563 // number of views.
564 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700565 GLTexture tex2D;
566 initOnePixelColorTexture2DSingleLayered(tex2D);
567
Martin Radev7cf61662017-07-26 17:10:53 +0300568 // The framebuffer has only 1 view.
Mingyu Hu7d64c482019-03-12 14:27:40 -0700569 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Martin Radev7cf61662017-07-26 17:10:53 +0300570
571 glDrawArrays(GL_TRIANGLES, 0, 3);
572 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
573
574 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
575 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
576 }
577
578 // Check that no errors are generated if the number of views in both program and draw
579 // framebuffer matches.
580 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700581 GLTexture tex2DArray;
582 initOnePixelColorTexture2DMultiLayered(tex2DArray);
583
584 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radev7cf61662017-07-26 17:10:53 +0300585
586 glDrawArrays(GL_TRIANGLES, 0, 3);
587 EXPECT_GL_NO_ERROR();
588
589 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
590 EXPECT_GL_NO_ERROR();
591 }
Martin Radevda8e2572017-09-12 17:21:16 +0300592}
Martin Radev7cf61662017-07-26 17:10:53 +0300593
Martin Radevda8e2572017-09-12 17:21:16 +0300594// The test verifies that glDraw* generates an INVALID_OPERATION error if the program does not use
595// the multiview extension, but the active draw framebuffer has more than one view.
596TEST_P(MultiviewDrawValidationTest, NumViewsMismatchForNonMultiviewProgram)
597{
598 if (!requestMultiviewExtension())
Martin Radev7cf61662017-07-26 17:10:53 +0300599 {
Martin Radevda8e2572017-09-12 17:21:16 +0300600 return;
Martin Radev7cf61662017-07-26 17:10:53 +0300601 }
Martin Radevda8e2572017-09-12 17:21:16 +0300602
Jamie Madill35cd7332018-12-02 12:03:33 -0500603 constexpr char kVS[] =
Martin Radevda8e2572017-09-12 17:21:16 +0300604 "#version 300 es\n"
605 "void main()\n"
606 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500607 constexpr char kFS[] =
Martin Radevda8e2572017-09-12 17:21:16 +0300608 "#version 300 es\n"
609 "precision mediump float;\n"
610 "void main()\n"
611 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500612 ANGLE_GL_PROGRAM(programNoMultiview, kVS, kFS);
Martin Radevda8e2572017-09-12 17:21:16 +0300613 glUseProgram(programNoMultiview);
614
Olli Etuaho44ae8992018-08-20 15:37:09 +0300615 GLVertexArray vao;
616 GLBuffer vertexBuffer;
617 GLBuffer indexBuffer;
618 initVAO(vao, vertexBuffer, indexBuffer);
619
620 GLFramebuffer fbo;
621 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
622
Mingyu Hu7d64c482019-03-12 14:27:40 -0700623 GLTexture tex2DArray;
624 initOnePixelColorTexture2DMultiLayered(tex2DArray);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300625
Mingyu Hu7d64c482019-03-12 14:27:40 -0700626 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radevda8e2572017-09-12 17:21:16 +0300627
628 glDrawArrays(GL_TRIANGLES, 0, 3);
629 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
630
631 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
632 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radev7cf61662017-07-26 17:10:53 +0300633}
634
Martin Radev7e69f762017-07-27 14:54:13 +0300635// The test verifies that glDraw*:
636// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
Jamie Madill3a256222018-12-08 09:56:39 -0500637// greater than 1 and there is an active not paused transform feedback object.
Martin Radev7e69f762017-07-27 14:54:13 +0300638// 2) does not generate any error if the number of views in the draw framebuffer is 1.
639TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
640{
Jamie Madill3a256222018-12-08 09:56:39 -0500641 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radev7e69f762017-07-27 14:54:13 +0300642
Jamie Madill35cd7332018-12-02 12:03:33 -0500643 constexpr char kVS[] = R"(#version 300 es
644out float tfVarying;
645void main()
646{
647 tfVarying = 1.0;
648})";
649
650 constexpr char kFS[] = R"(#version 300 es
651precision mediump float;
652void main()
653{})";
Jamie Madill04c084d2018-08-08 15:49:28 -0400654
Olli Etuaho3755c482017-10-13 15:40:26 +0300655 std::vector<std::string> tfVaryings;
Jamie Madill04c084d2018-08-08 15:49:28 -0400656 tfVaryings.emplace_back("tfVarying");
Jamie Madill35cd7332018-12-02 12:03:33 -0500657 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(singleViewProgram, kVS, kFS, tfVaryings,
Olli Etuaho3755c482017-10-13 15:40:26 +0300658 GL_SEPARATE_ATTRIBS);
Jamie Madill04c084d2018-08-08 15:49:28 -0400659
660 std::vector<std::string> dualViewTFVaryings;
661 dualViewTFVaryings.emplace_back("gl_Position");
662 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(dualViewProgram, kDualViewVSSource, kDualViewFSSource,
663 dualViewTFVaryings, GL_SEPARATE_ATTRIBS);
Martin Radev7e69f762017-07-27 14:54:13 +0300664
Olli Etuaho44ae8992018-08-20 15:37:09 +0300665 GLVertexArray vao;
666 GLBuffer vertexBuffer;
667 GLBuffer indexBuffer;
668 initVAO(vao, vertexBuffer, indexBuffer);
669
Martin Radev7e69f762017-07-27 14:54:13 +0300670 GLBuffer tbo;
671 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
Jamie Madill04c084d2018-08-08 15:49:28 -0400672 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 16u, nullptr, GL_STATIC_DRAW);
Martin Radev7e69f762017-07-27 14:54:13 +0300673
674 GLTransformFeedback transformFeedback;
675 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
Olli Etuaho3755c482017-10-13 15:40:26 +0300676
677 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
678
Jamie Madill04c084d2018-08-08 15:49:28 -0400679 glUseProgram(dualViewProgram);
Martin Radev7e69f762017-07-27 14:54:13 +0300680 glBeginTransformFeedback(GL_TRIANGLES);
681 ASSERT_GL_NO_ERROR();
682
Olli Etuaho44ae8992018-08-20 15:37:09 +0300683 GLFramebuffer fbo;
684 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
685
Mingyu Hu7d64c482019-03-12 14:27:40 -0700686 GLTexture tex2DArray;
687 initOnePixelColorTexture2DMultiLayered(tex2DArray);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300688
shrekshao15ce8222019-03-18 19:25:21 -0700689 GLenum bufs[] = {GL_NONE};
690 glDrawBuffers(1, bufs);
691
Martin Radev7e69f762017-07-27 14:54:13 +0300692 // Check that drawArrays generates an error when there is an active transform feedback object
693 // and the number of views in the draw framebuffer is greater than 1.
694 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700695 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radev7e69f762017-07-27 14:54:13 +0300696 glDrawArrays(GL_TRIANGLES, 0, 3);
697 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
698 }
699
Jamie Madill04c084d2018-08-08 15:49:28 -0400700 glEndTransformFeedback();
701
702 // Ending transform feedback should allow the draw to succeed.
703 {
704 glDrawArrays(GL_TRIANGLES, 0, 3);
705 EXPECT_GL_NO_ERROR();
706 }
707
Jamie Madill3a256222018-12-08 09:56:39 -0500708 // A paused transform feedback should not trigger an error.
Jamie Madill04c084d2018-08-08 15:49:28 -0400709 glBeginTransformFeedback(GL_TRIANGLES);
710 glPauseTransformFeedback();
711 ASSERT_GL_NO_ERROR();
712
713 glDrawArrays(GL_TRIANGLES, 0, 3);
Jamie Madill3a256222018-12-08 09:56:39 -0500714 ASSERT_GL_NO_ERROR();
Jamie Madill04c084d2018-08-08 15:49:28 -0400715
716 // Unbind transform feedback - should succeed.
717 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
718 glDrawArrays(GL_TRIANGLES, 0, 3);
719 ASSERT_GL_NO_ERROR();
720
Jamie Madill3a256222018-12-08 09:56:39 -0500721 // Rebind paused transform feedback - should succeed.
Jamie Madill04c084d2018-08-08 15:49:28 -0400722 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
723 glDrawArrays(GL_TRIANGLES, 0, 3);
Jamie Madill3a256222018-12-08 09:56:39 -0500724 ASSERT_GL_NO_ERROR();
Jamie Madill04c084d2018-08-08 15:49:28 -0400725
726 glResumeTransformFeedback();
727 glEndTransformFeedback();
728
729 glUseProgram(singleViewProgram);
730 glBeginTransformFeedback(GL_TRIANGLES);
731 ASSERT_GL_NO_ERROR();
732
Mingyu Hu7d64c482019-03-12 14:27:40 -0700733 GLTexture tex2D;
734 initOnePixelColorTexture2DSingleLayered(tex2D);
735
Martin Radev7e69f762017-07-27 14:54:13 +0300736 // Check that drawArrays does not generate an error when the number of views in the draw
737 // framebuffer is 1.
738 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700739 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Martin Radev7e69f762017-07-27 14:54:13 +0300740 glDrawArrays(GL_TRIANGLES, 0, 3);
741 EXPECT_GL_NO_ERROR();
742 }
743
744 glEndTransformFeedback();
745}
746
Martin Radevffe754b2017-07-31 10:38:07 +0300747// The test verifies that glDraw*:
748// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
749// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
750// 2) does not generate any error if the number of views in the draw framebuffer is 1.
751TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
752{
Yunchao He9550c602018-02-13 14:47:05 +0800753 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Jamie Madillb8149072019-04-30 16:14:44 -0400754 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_disjoint_timer_query"));
Martin Radevffe754b2017-07-31 10:38:07 +0300755
Olli Etuaho44ae8992018-08-20 15:37:09 +0300756 ANGLE_GL_PROGRAM(dualViewProgram, kDualViewVSSource, kDualViewFSSource);
757
Jamie Madill35cd7332018-12-02 12:03:33 -0500758 constexpr char kVS[] =
Martin Radevffe754b2017-07-31 10:38:07 +0300759 "#version 300 es\n"
760 "void main()\n"
761 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500762 constexpr char kFS[] =
Martin Radevffe754b2017-07-31 10:38:07 +0300763 "#version 300 es\n"
764 "precision mediump float;\n"
765 "void main()\n"
766 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500767 ANGLE_GL_PROGRAM(singleViewProgram, kVS, kFS);
Jamie Madill04c084d2018-08-08 15:49:28 -0400768 glUseProgram(singleViewProgram);
Martin Radevffe754b2017-07-31 10:38:07 +0300769
Olli Etuaho44ae8992018-08-20 15:37:09 +0300770 GLVertexArray vao;
771 GLBuffer vertexBuffer;
772 GLBuffer indexBuffer;
773 initVAO(vao, vertexBuffer, indexBuffer);
774
Martin Radevffe754b2017-07-31 10:38:07 +0300775 GLuint query = 0u;
776 glGenQueriesEXT(1, &query);
777 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
778
Olli Etuaho44ae8992018-08-20 15:37:09 +0300779 GLFramebuffer fbo;
780 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
781
Mingyu Hu7d64c482019-03-12 14:27:40 -0700782 GLTexture tex2DArr;
783 initOnePixelColorTexture2DMultiLayered(tex2DArr);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300784
shrekshao15ce8222019-03-18 19:25:21 -0700785 GLenum bufs[] = {GL_NONE};
786 glDrawBuffers(1, bufs);
787
Martin Radevffe754b2017-07-31 10:38:07 +0300788 // Check first case.
789 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300790 glUseProgram(dualViewProgram);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700791 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArr, 0, 0, 2);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300792 glClear(GL_COLOR_BUFFER_BIT);
793 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radevffe754b2017-07-31 10:38:07 +0300794 glDrawArrays(GL_TRIANGLES, 0, 3);
795 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
796 }
797
Mingyu Hu7d64c482019-03-12 14:27:40 -0700798 GLTexture tex2D;
799 initOnePixelColorTexture2DSingleLayered(tex2D);
800
Martin Radevffe754b2017-07-31 10:38:07 +0300801 // Check second case.
802 {
Jamie Madill04c084d2018-08-08 15:49:28 -0400803 glUseProgram(singleViewProgram);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700804 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300805 glClear(GL_COLOR_BUFFER_BIT);
806 EXPECT_GL_NO_ERROR();
Martin Radevffe754b2017-07-31 10:38:07 +0300807 glDrawArrays(GL_TRIANGLES, 0, 3);
808 EXPECT_GL_NO_ERROR();
809 }
810
811 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
812 glDeleteQueries(1, &query);
Jamie Madill04c084d2018-08-08 15:49:28 -0400813
814 // Check starting a query after a successful draw.
815 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300816 glUseProgram(dualViewProgram);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700817 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArr, 0, 0, 2);
Jamie Madill04c084d2018-08-08 15:49:28 -0400818 glClear(GL_COLOR_BUFFER_BIT);
819 EXPECT_GL_NO_ERROR();
820 glDrawArrays(GL_TRIANGLES, 0, 3);
821 EXPECT_GL_NO_ERROR();
822
823 glGenQueriesEXT(1, &query);
824 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
825
826 glDrawArrays(GL_TRIANGLES, 0, 3);
827 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
828
829 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
830 glDrawArrays(GL_TRIANGLES, 0, 3);
831 EXPECT_GL_NO_ERROR();
832
833 glDeleteQueries(1, &query);
834 }
Martin Radevffe754b2017-07-31 10:38:07 +0300835}
836
Martin Radev8f276e22017-05-30 12:05:52 +0300837// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300838TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300839{
Jamie Madill3a256222018-12-08 09:56:39 -0500840 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
841
Martin Radev8f276e22017-05-30 12:05:52 +0300842 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
843 ASSERT_GL_NO_ERROR();
844
845 checkOutput();
846}
847
848// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300849TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300850{
Jamie Madill3a256222018-12-08 09:56:39 -0500851 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
852
Martin Radev8f276e22017-05-30 12:05:52 +0300853 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
854 ASSERT_GL_NO_ERROR();
855
856 checkOutput();
857}
858
859// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300860TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300861{
Jamie Madill3a256222018-12-08 09:56:39 -0500862 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
863
Martin Radev8f276e22017-05-30 12:05:52 +0300864 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
865 ASSERT_GL_NO_ERROR();
866
867 checkOutput();
868}
869
870// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300871TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300872{
Jamie Madill3a256222018-12-08 09:56:39 -0500873 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev8f276e22017-05-30 12:05:52 +0300874
Jamie Madill35cd7332018-12-02 12:03:33 -0500875 constexpr char kVS[] =
Martin Radev8f276e22017-05-30 12:05:52 +0300876 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700877 "#extension GL_OVR_multiview2 : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300878 "layout(num_views = 4) in;\n"
879 "in vec4 vPosition;\n"
880 "void main()\n"
881 "{\n"
882 " if (gl_ViewID_OVR == 0u) {\n"
883 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
884 " } else if (gl_ViewID_OVR == 1u) {\n"
885 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
886 " } else if (gl_ViewID_OVR == 2u) {\n"
887 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
888 " } else {\n"
889 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
890 " }"
891 " gl_Position.yzw = vPosition.yzw;\n"
892 "}\n";
893
Jamie Madill35cd7332018-12-02 12:03:33 -0500894 constexpr char kFS[] =
Martin Radev8f276e22017-05-30 12:05:52 +0300895 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700896 "#extension GL_OVR_multiview2 : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300897 "precision mediump float;\n"
898 "out vec4 col;\n"
899 "void main()\n"
900 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300901 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300902 "}\n";
903
Olli Etuaho4836acc2018-08-20 15:23:18 +0300904 updateFBOs(4, 1, 4);
Jamie Madill35cd7332018-12-02 12:03:33 -0500905 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev8f276e22017-05-30 12:05:52 +0300906
907 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
908 ASSERT_GL_NO_ERROR();
909
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300910 resolveMultisampledFBO();
Martin Radev8f276e22017-05-30 12:05:52 +0300911 for (int i = 0; i < 4; ++i)
912 {
913 for (int j = 0; j < 4; ++j)
914 {
Martin Radev8f276e22017-05-30 12:05:52 +0300915 if (i == j)
916 {
Martin Radev67a8a012017-09-08 13:03:52 +0300917 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300918 }
919 else
920 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300921 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300922 }
923 }
924 }
925 EXPECT_GL_NO_ERROR();
926}
927
928// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300929TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +0300930{
Jamie Madill3a256222018-12-08 09:56:39 -0500931 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev8f276e22017-05-30 12:05:52 +0300932
Jamie Madill35cd7332018-12-02 12:03:33 -0500933 constexpr char kVS[] =
Martin Radev8f276e22017-05-30 12:05:52 +0300934 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700935 "#extension GL_OVR_multiview2 : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300936 "layout(num_views = 2) in;\n"
937 "in vec4 vPosition;\n"
938 "void main()\n"
939 "{\n"
940 " vec4 p = vPosition;\n"
941 " if (gl_InstanceID == 1){\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300942 " p.y = p.y * 0.5 + 0.5;\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300943 " } else {\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300944 " p.y = p.y * 0.5 - 0.5;\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300945 " }\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300946 " 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 +0300947 " gl_Position.yzw = p.yzw;\n"
948 "}\n";
949
Jamie Madill35cd7332018-12-02 12:03:33 -0500950 constexpr char kFS[] =
Martin Radev8f276e22017-05-30 12:05:52 +0300951 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700952 "#extension GL_OVR_multiview2 : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300953 "precision mediump float;\n"
954 "out vec4 col;\n"
955 "void main()\n"
956 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300957 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300958 "}\n";
959
Martin Radev3c25ad02017-08-22 17:36:53 +0300960 const int kViewWidth = 2;
961 const int kViewHeight = 2;
962 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300963 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Jamie Madill35cd7332018-12-02 12:03:33 -0500964 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev8f276e22017-05-30 12:05:52 +0300965
Martin Radev67a8a012017-09-08 13:03:52 +0300966 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 2u);
Martin Radev8f276e22017-05-30 12:05:52 +0300967 ASSERT_GL_NO_ERROR();
968
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300969 resolveMultisampledFBO();
970
Martin Radev67a8a012017-09-08 13:03:52 +0300971 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
972 {{255, 0}, {255, 0}}};
Martin Radev3c25ad02017-08-22 17:36:53 +0300973
974 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +0300975 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300976 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +0300977 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300978 for (int x = 0; x < 2; ++x)
979 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300980 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][y][x], 0,
981 expectedGreenChannel[view][y][x]),
Martin Radev3c25ad02017-08-22 17:36:53 +0300982 GetViewColor(x, y, view));
983 }
Martin Radev8f276e22017-05-30 12:05:52 +0300984 }
985 }
986}
987
Martin Radev553590a2017-07-31 16:40:39 +0300988// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
989// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
990// offset of each quad are passed as separate attributes which are indexed based on the
991// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
992// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
993// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
994// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +0300995TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +0300996{
Jamie Madill3a256222018-12-08 09:56:39 -0500997 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev553590a2017-07-31 16:40:39 +0300998
Corentin Wallez02cd1522018-08-22 13:46:21 +0200999 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001000 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001001 if (IsWindows() && IsD3D11())
1002 {
1003 ignoreD3D11SDKLayersWarnings();
1004 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001005
Jamie Madill35cd7332018-12-02 12:03:33 -05001006 constexpr char kVS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001007 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001008 "#extension GL_OVR_multiview2 : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001009 "layout(num_views = 2) in;\n"
1010 "in vec3 vPosition;\n"
1011 "in float offsetX;\n"
1012 "in float offsetY;\n"
1013 "void main()\n"
1014 "{\n"
1015 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001016 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001017 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
1018 " gl_Position.yzw = p.yzw;\n"
1019 "}\n";
1020
Jamie Madill35cd7332018-12-02 12:03:33 -05001021 constexpr char kFS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001022 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001023 "#extension GL_OVR_multiview2 : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001024 "precision mediump float;\n"
1025 "out vec4 col;\n"
1026 "void main()\n"
1027 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001028 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001029 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +03001030
1031 const int kViewWidth = 4;
1032 const int kViewHeight = 4;
1033 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001034 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Jamie Madill35cd7332018-12-02 12:03:33 -05001035 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev553590a2017-07-31 16:40:39 +03001036
1037 GLBuffer xOffsetVBO;
1038 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1039 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
1040 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
1041 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1042 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1043 glVertexAttribDivisor(xOffsetLoc, 3);
1044 glEnableVertexAttribArray(xOffsetLoc);
1045
1046 GLBuffer yOffsetVBO;
1047 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1048 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1049 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1050 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1051 glVertexAttribDivisor(yOffsetLoc, 1);
1052 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1053 glEnableVertexAttribArray(yOffsetLoc);
1054
Martin Radev67a8a012017-09-08 13:03:52 +03001055 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev553590a2017-07-31 16:40:39 +03001056 ASSERT_GL_NO_ERROR();
1057
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001058 resolveMultisampledFBO();
1059
Martin Radev67a8a012017-09-08 13:03:52 +03001060 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001061 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1062 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1063 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +03001064 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001065 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +03001066 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001067 for (int col = 0; col < 4; ++col)
1068 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001069 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0,
1070 expectedGreenChannel[view][row][col]),
Martin Radev3c25ad02017-08-22 17:36:53 +03001071 GetViewColor(col, row, view));
1072 }
Martin Radev553590a2017-07-31 16:40:39 +03001073 }
1074 }
1075}
1076
1077// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1078// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +03001079TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +03001080{
Jamie Madill3a256222018-12-08 09:56:39 -05001081 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev553590a2017-07-31 16:40:39 +03001082
Olli Etuaho4836acc2018-08-20 15:23:18 +03001083 updateFBOs(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +03001084
1085 // Create multiview program.
Jamie Madill35cd7332018-12-02 12:03:33 -05001086 constexpr char kVS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001087 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001088 "#extension GL_OVR_multiview2 : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001089 "layout(num_views = 2) in;\n"
1090 "layout(location = 0) in vec2 vPosition;\n"
1091 "layout(location = 1) in float offsetX;\n"
1092 "void main()\n"
1093 "{\n"
1094 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1095 " p.x += offsetX;\n"
1096 " gl_Position = p;\n"
1097 "}\n";
1098
Jamie Madill35cd7332018-12-02 12:03:33 -05001099 constexpr char kFS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001100 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001101 "#extension GL_OVR_multiview2 : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001102 "precision mediump float;\n"
1103 "out vec4 col;\n"
1104 "void main()\n"
1105 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001106 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001107 "}\n";
1108
Jamie Madill35cd7332018-12-02 12:03:33 -05001109 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev553590a2017-07-31 16:40:39 +03001110
Jamie Madill35cd7332018-12-02 12:03:33 -05001111 constexpr char kDummyVS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001112 "#version 300 es\n"
1113 "layout(location = 0) in vec2 vPosition;\n"
1114 "layout(location = 1) in float offsetX;\n"
1115 "void main()\n"
1116 "{\n"
1117 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1118 "}\n";
1119
Jamie Madill35cd7332018-12-02 12:03:33 -05001120 constexpr char kDummyFS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001121 "#version 300 es\n"
1122 "precision mediump float;\n"
1123 "out vec4 col;\n"
1124 "void main()\n"
1125 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001126 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001127 "}\n";
1128
Jamie Madill35cd7332018-12-02 12:03:33 -05001129 ANGLE_GL_PROGRAM(dummyProgram, kDummyVS, kDummyFS);
Martin Radev553590a2017-07-31 16:40:39 +03001130
1131 GLBuffer xOffsetVBO;
1132 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1133 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1134 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1135 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1136
1137 GLBuffer vertexVBO;
1138 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1139 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1140 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1141 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1142
1143 GLVertexArray vao[2];
1144 for (size_t i = 0u; i < 2u; ++i)
1145 {
1146 glBindVertexArray(vao[i]);
1147
1148 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1149 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1150 glEnableVertexAttribArray(0);
1151
1152 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1153 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1154 glEnableVertexAttribArray(1);
1155 }
1156 ASSERT_GL_NO_ERROR();
1157
1158 glViewport(0, 0, 1, 1);
1159 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001160 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001161 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001162
1163 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1164 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1165 // bits are cleared.
1166 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001167 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1168 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001169 glBindVertexArray(vao[0]);
1170 glVertexAttribDivisor(1, 0);
1171 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1172 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001173 ASSERT_GL_NO_ERROR();
1174
1175 // Check that vertexAttribDivisor uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001176 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001177 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001178 glUseProgram(program);
1179 glVertexAttribDivisor(1, 1);
1180 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001181
1182 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001183 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1184 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001185
1186 // Clear the buffers and propagate divisor to the driver.
1187 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1188 // dirty bits when useProgram is called.
1189 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001190 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1191 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001192 glVertexAttribDivisor(1, 1);
1193 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1194 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001195 ASSERT_GL_NO_ERROR();
1196
1197 // Check that useProgram uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001198 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001199 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001200 glUseProgram(program);
1201 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001202
1203 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001204 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1205 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001206
1207 // We go through similar steps as before.
1208 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001209 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1210 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001211 glVertexAttribDivisor(1, 1);
1212 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1213 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001214 ASSERT_GL_NO_ERROR();
1215
1216 // Check that bindVertexArray uses the number of views to update the divisor.
1217 {
1218 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1219 // divisor for vao[1] only.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001220 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001221 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001222 glBindVertexArray(vao[1]);
1223 glUseProgram(program);
1224 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001225 glBindVertexArray(0);
1226 ASSERT_GL_NO_ERROR();
1227 }
1228 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1229 // adjusts the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001230 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001231 glBindVertexArray(vao[0]);
1232 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001233
1234 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001235 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1236 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001237}
1238
Martin Radev0d671c92017-08-10 16:41:52 +03001239// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1240// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001241TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001242{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001243 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1244 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001245
Jamie Madill35cd7332018-12-02 12:03:33 -05001246 constexpr char kVS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001247 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001248 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001249 "layout(num_views = 2) in;\n"
1250 "in vec3 vPosition;\n"
1251 "void main()\n"
1252 "{\n"
1253 " gl_Position.x = 2.0;\n"
1254 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1255 "}\n";
1256
Jamie Madill35cd7332018-12-02 12:03:33 -05001257 constexpr char kFS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001258 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001259 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001260 "precision mediump float;\n"
1261 "out vec4 col;\n"
1262 "void main()\n"
1263 "{\n"
1264 " col = vec4(1,0,0,0);\n"
1265 "}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -05001266 ANGLE_GL_PROGRAM(program, kVS, kFS);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001267 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001268
1269 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1270 ASSERT_GL_NO_ERROR();
1271 EXPECT_GL_FALSE(result);
1272}
1273
1274// Test that there are fragments passing the occlusion query if only view 0 can produce
1275// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001276TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001277{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001278 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1279 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001280
Jamie Madill35cd7332018-12-02 12:03:33 -05001281 constexpr char kVS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001282 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001283 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001284 "layout(num_views = 2) in;\n"
1285 "in vec3 vPosition;\n"
1286 "void main()\n"
1287 "{\n"
1288 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1289 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1290 "}\n";
1291
Jamie Madill35cd7332018-12-02 12:03:33 -05001292 constexpr char kFS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001293 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001294 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001295 "precision mediump float;\n"
1296 "out vec4 col;\n"
1297 "void main()\n"
1298 "{\n"
1299 " col = vec4(1,0,0,0);\n"
1300 "}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -05001301 ANGLE_GL_PROGRAM(program, kVS, kFS);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001302 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001303
1304 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1305 ASSERT_GL_NO_ERROR();
1306 EXPECT_GL_TRUE(result);
1307}
1308
1309// Test that there are fragments passing the occlusion query if only view 1 can produce
1310// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001311TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001312{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001313 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1314 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001315
Jamie Madill35cd7332018-12-02 12:03:33 -05001316 constexpr char kVS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001317 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001318 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001319 "layout(num_views = 2) in;\n"
1320 "in vec3 vPosition;\n"
1321 "void main()\n"
1322 "{\n"
1323 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1324 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1325 "}\n";
1326
Jamie Madill35cd7332018-12-02 12:03:33 -05001327 constexpr char kFS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001328 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001329 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001330 "precision mediump float;\n"
1331 "out vec4 col;\n"
1332 "void main()\n"
1333 "{\n"
1334 " col = vec4(1,0,0,0);\n"
1335 "}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -05001336 ANGLE_GL_PROGRAM(program, kVS, kFS);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001337 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001338
1339 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1340 ASSERT_GL_NO_ERROR();
1341 EXPECT_GL_TRUE(result);
1342}
1343
Martin Radev41ac68e2017-06-06 12:16:58 +03001344// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1345// compiles and links without an error.
1346TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1347{
1348 if (!requestMultiviewExtension())
1349 {
1350 return;
1351 }
1352
Jamie Madill35cd7332018-12-02 12:03:33 -05001353 constexpr char kVS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001354 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001355 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001356 "layout(num_views = 2) in;\n"
1357 "void main()\n"
1358 "{\n"
1359 "}\n";
1360
Jamie Madill35cd7332018-12-02 12:03:33 -05001361 constexpr char kFS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001362 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001363 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001364 "precision mediump float;\n"
1365 "void main()\n"
1366 "{\n"
1367 "}\n";
1368
Jamie Madill35cd7332018-12-02 12:03:33 -05001369 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev41ac68e2017-06-06 12:16:58 +03001370 glUseProgram(program);
1371
1372 EXPECT_GL_NO_ERROR();
1373}
1374
1375// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1376// without an error.
1377TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1378{
1379 if (!requestMultiviewExtension())
1380 {
1381 return;
1382 }
1383
Jamie Madill35cd7332018-12-02 12:03:33 -05001384 constexpr char kVS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001385 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001386 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001387 "layout(num_views = 2) in;\n"
1388 "void main()\n"
1389 "{\n"
1390 " if (gl_ViewID_OVR == 0u) {\n"
1391 " gl_Position = vec4(1,0,0,1);\n"
1392 " } else {\n"
1393 " gl_Position = vec4(-1,0,0,1);\n"
1394 " }\n"
1395 "}\n";
1396
Jamie Madill35cd7332018-12-02 12:03:33 -05001397 constexpr char kFS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001398 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001399 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001400 "precision mediump float;\n"
1401 "void main()\n"
1402 "{\n"
1403 "}\n";
1404
Jamie Madill35cd7332018-12-02 12:03:33 -05001405 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev41ac68e2017-06-06 12:16:58 +03001406 glUseProgram(program);
1407
1408 EXPECT_GL_NO_ERROR();
1409}
1410
1411// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1412// without an error.
1413TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1414{
1415 if (!requestMultiviewExtension())
1416 {
1417 return;
1418 }
1419
Jamie Madill35cd7332018-12-02 12:03:33 -05001420 constexpr char kVS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001421 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001422 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001423 "layout(num_views = 2) in;\n"
1424 "void main()\n"
1425 "{\n"
1426 "}\n";
1427
Jamie Madill35cd7332018-12-02 12:03:33 -05001428 constexpr char kFS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001429 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001430 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001431 "precision mediump float;\n"
1432 "out vec4 col;\n"
1433 "void main()\n"
1434 "{\n"
1435 " if (gl_ViewID_OVR == 0u) {\n"
1436 " col = vec4(1,0,0,1);\n"
1437 " } else {\n"
1438 " col = vec4(-1,0,0,1);\n"
1439 " }\n"
1440 "}\n";
1441
Jamie Madill35cd7332018-12-02 12:03:33 -05001442 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev41ac68e2017-06-06 12:16:58 +03001443 glUseProgram(program);
1444
1445 EXPECT_GL_NO_ERROR();
1446}
1447
Martin Radev61bd9992017-08-11 13:10:55 +03001448// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001449TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001450{
1451 if (!requestMultiviewExtension())
1452 {
1453 return;
1454 }
1455
Geoff Lang25858162017-11-06 11:25:58 -05001456 // Test failing on P400 graphics card (anglebug.com/2228)
1457 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1458
Jamie Madill35cd7332018-12-02 12:03:33 -05001459 constexpr char kVS[] =
Martin Radev61bd9992017-08-11 13:10:55 +03001460 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001461 "#extension GL_OVR_multiview2 : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001462 "layout(num_views = 2) in;\n"
1463 "layout(location=0) in vec2 vPosition;\n"
1464 "void main()\n"
1465 "{\n"
1466 " gl_PointSize = 1.0;\n"
1467 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1468 "}\n";
1469
Jamie Madill35cd7332018-12-02 12:03:33 -05001470 constexpr char kFS[] =
Martin Radev61bd9992017-08-11 13:10:55 +03001471 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001472 "#extension GL_OVR_multiview2 : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001473 "precision mediump float;\n"
1474 "out vec4 col;\n"
1475 "void main()\n"
1476 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001477 " col = vec4(0,1,0,1);\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001478 "}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -05001479 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev61bd9992017-08-11 13:10:55 +03001480 glUseProgram(program);
1481
Martin Radev3c25ad02017-08-22 17:36:53 +03001482 const int kViewWidth = 4;
1483 const int kViewHeight = 2;
1484 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001485 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001486
1487 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1488 std::vector<Vector2> vertexDataInClipSpace =
1489 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1490 setupGeometry(vertexDataInClipSpace);
1491
1492 glDrawArrays(GL_POINTS, 0, 2);
1493
Martin Radev67a8a012017-09-08 13:03:52 +03001494 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001495 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001496 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001497}
1498
1499// The test checks that GL_LINES is correctly rendered.
1500// The behavior of this test is not guaranteed by the spec:
1501// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1502// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1503// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1504// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001505TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001506{
1507 if (!requestMultiviewExtension())
1508 {
1509 return;
1510 }
1511
Martin Radevced5c862017-08-17 16:05:29 +03001512 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001513 ASSERT_NE(program, 0u);
1514 glUseProgram(program);
1515 ASSERT_GL_NO_ERROR();
1516
Martin Radev3c25ad02017-08-22 17:36:53 +03001517 const int kViewWidth = 4;
1518 const int kViewHeight = 2;
1519 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001520 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001521
1522 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1523 std::vector<Vector2> vertexDataInClipSpace =
1524 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1525 setupGeometry(vertexDataInClipSpace);
1526
1527 glDrawArrays(GL_LINES, 0, 2);
1528
Martin Radev67a8a012017-09-08 13:03:52 +03001529 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001530 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001531 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001532
1533 glDeleteProgram(program);
1534}
1535
1536// The test checks that GL_LINE_STRIP is correctly rendered.
1537// The behavior of this test is not guaranteed by the spec:
1538// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1539// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1540// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1541// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001542TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001543{
1544 if (!requestMultiviewExtension())
1545 {
1546 return;
1547 }
1548
Martin Radevced5c862017-08-17 16:05:29 +03001549 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001550 ASSERT_NE(program, 0u);
1551 glUseProgram(program);
1552 ASSERT_GL_NO_ERROR();
1553
Martin Radev3c25ad02017-08-22 17:36:53 +03001554 const int kViewWidth = 4;
1555 const int kViewHeight = 2;
1556 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001557 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001558
1559 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1560 std::vector<Vector2> vertexDataInClipSpace =
1561 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1562 setupGeometry(vertexDataInClipSpace);
1563
1564 glDrawArrays(GL_LINE_STRIP, 0, 3);
1565
Martin Radev67a8a012017-09-08 13:03:52 +03001566 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001567 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001568 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001569
1570 glDeleteProgram(program);
1571}
1572
1573// The test checks that GL_LINE_LOOP is correctly rendered.
1574// The behavior of this test is not guaranteed by the spec:
1575// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1576// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1577// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1578// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001579TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001580{
1581 if (!requestMultiviewExtension())
1582 {
1583 return;
1584 }
1585
Martin Radevced5c862017-08-17 16:05:29 +03001586 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001587 ASSERT_NE(program, 0u);
1588 glUseProgram(program);
1589 ASSERT_GL_NO_ERROR();
1590
Martin Radev3c25ad02017-08-22 17:36:53 +03001591 const int kViewWidth = 4;
1592 const int kViewHeight = 4;
1593 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001594 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001595
1596 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1597 Vector2I(0, 3)};
1598 std::vector<Vector2> vertexDataInClipSpace =
1599 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1600 setupGeometry(vertexDataInClipSpace);
1601
1602 glDrawArrays(GL_LINE_LOOP, 0, 4);
1603
Martin Radev67a8a012017-09-08 13:03:52 +03001604 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001605 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1606 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001607 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001608
1609 glDeleteProgram(program);
1610}
1611
1612// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001613TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001614{
1615 if (!requestMultiviewExtension())
1616 {
1617 return;
1618 }
1619
Martin Radevced5c862017-08-17 16:05:29 +03001620 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001621 ASSERT_NE(program, 0u);
1622 glUseProgram(program);
1623 ASSERT_GL_NO_ERROR();
1624
1625 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1626 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1627 setupGeometry(vertexDataInClipSpace);
1628
Martin Radev3c25ad02017-08-22 17:36:53 +03001629 const int kViewWidth = 2;
1630 const int kViewHeight = 2;
1631 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001632 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001633
1634 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1635
Martin Radev67a8a012017-09-08 13:03:52 +03001636 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1637 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1638 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001639
1640 glDeleteProgram(program);
1641}
1642
1643// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001644TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001645{
1646 if (!requestMultiviewExtension())
1647 {
1648 return;
1649 }
1650
Martin Radevced5c862017-08-17 16:05:29 +03001651 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001652 ASSERT_NE(program, 0u);
1653 glUseProgram(program);
1654 ASSERT_GL_NO_ERROR();
1655
1656 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1657 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1658 setupGeometry(vertexDataInClipSpace);
1659
Martin Radev3c25ad02017-08-22 17:36:53 +03001660 const int kViewWidth = 2;
1661 const int kViewHeight = 2;
1662 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001663 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001664
1665 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1666
Martin Radev67a8a012017-09-08 13:03:52 +03001667 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1668 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1669 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001670
1671 glDeleteProgram(program);
1672}
1673
Martin Radev0abb7a22017-08-28 15:34:45 +03001674// Verify that re-linking a program adjusts the attribute divisor.
1675// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1676// to each other. The quads' position and color depend on the corresponding attribute divisors.
1677TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1678{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001679 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev0abb7a22017-08-28 15:34:45 +03001680 {
1681 return;
1682 }
1683
Corentin Wallez02cd1522018-08-22 13:46:21 +02001684 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001685 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001686 if (IsWindows() && IsD3D11())
1687 {
1688 ignoreD3D11SDKLayersWarnings();
1689 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001690
Martin Radev0abb7a22017-08-28 15:34:45 +03001691 const int kViewWidth = 4;
1692 const int kViewHeight = 1;
1693 const int kNumViews = 2;
1694
Jamie Madill35cd7332018-12-02 12:03:33 -05001695 constexpr char kFS[] =
Martin Radev0abb7a22017-08-28 15:34:45 +03001696 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001697 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001698 "precision mediump float;\n"
1699 "in vec4 oColor;\n"
1700 "out vec4 col;\n"
1701 "void main()\n"
1702 "{\n"
1703 " col = oColor;\n"
1704 "}\n";
1705
1706 auto generateVertexShaderSource = [](int numViews) -> std::string {
1707 std::string source =
1708 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001709 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001710 "layout(num_views = " +
1711 ToString(numViews) +
1712 ") in;\n"
1713 "in vec3 vPosition;\n"
1714 "in float vOffsetX;\n"
1715 "in vec4 vColor;\n"
1716 "out vec4 oColor;\n"
1717 "void main()\n"
1718 "{\n"
1719 " vec4 p = vec4(vPosition, 1.);\n"
1720 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1721 " oColor = vColor;\n"
1722 " gl_Position = p;\n"
1723 "}\n";
1724 return source;
1725 };
1726
1727 std::string vsSource = generateVertexShaderSource(kNumViews);
Jamie Madill35cd7332018-12-02 12:03:33 -05001728 ANGLE_GL_PROGRAM(program, vsSource.c_str(), kFS);
Martin Radev0abb7a22017-08-28 15:34:45 +03001729 glUseProgram(program);
1730
1731 GLint positionLoc;
1732 GLBuffer xOffsetVBO;
1733 GLint xOffsetLoc;
1734 GLBuffer colorVBO;
1735 GLint colorLoc;
1736
1737 {
1738 // Initialize buffers and setup attributes.
1739 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1740 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1741 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1742 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1743 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1744 glVertexAttribDivisor(xOffsetLoc, 1);
1745 glEnableVertexAttribArray(xOffsetLoc);
1746
1747 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1748 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1749 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1750 colorLoc = glGetAttribLocation(program, "vColor");
1751 glVertexAttribDivisor(colorLoc, 2);
1752 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1753 glEnableVertexAttribArray(colorLoc);
1754
1755 positionLoc = glGetAttribLocation(program, "vPosition");
1756 }
1757
1758 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001759 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001760
Martin Radev67a8a012017-09-08 13:03:52 +03001761 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001762 ASSERT_GL_NO_ERROR();
1763
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001764 resolveMultisampledFBO();
Martin Radev0abb7a22017-08-28 15:34:45 +03001765 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1766 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1767 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1768 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1769 }
1770
1771 {
1772 const int kNewNumViews = 3;
1773 vsSource = generateVertexShaderSource(kNewNumViews);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001774 updateFBOs(kViewWidth, kViewHeight, kNewNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001775
Jamie Madill35cd7332018-12-02 12:03:33 -05001776 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource.c_str());
Martin Radev0abb7a22017-08-28 15:34:45 +03001777 ASSERT_NE(0u, vs);
Jamie Madill35cd7332018-12-02 12:03:33 -05001778 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
Martin Radev0abb7a22017-08-28 15:34:45 +03001779 ASSERT_NE(0u, fs);
1780
1781 GLint numAttachedShaders = 0;
1782 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1783
1784 GLuint attachedShaders[2] = {0u};
1785 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1786 for (int i = 0; i < 2; ++i)
1787 {
1788 glDetachShader(program, attachedShaders[i]);
1789 }
1790
1791 glAttachShader(program, vs);
1792 glDeleteShader(vs);
1793
1794 glAttachShader(program, fs);
1795 glDeleteShader(fs);
1796
1797 glBindAttribLocation(program, positionLoc, "vPosition");
1798 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1799 glBindAttribLocation(program, colorLoc, "vColor");
1800
1801 glLinkProgram(program);
1802
Martin Radev67a8a012017-09-08 13:03:52 +03001803 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001804 ASSERT_GL_NO_ERROR();
1805
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001806 resolveMultisampledFBO();
Martin Radev0abb7a22017-08-28 15:34:45 +03001807 for (int i = 0; i < kNewNumViews; ++i)
1808 {
1809 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1810 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1811 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1812 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1813 }
1814 }
1815}
1816
Martin Radevced5c862017-08-17 16:05:29 +03001817// Test that useProgram applies the number of views in computing the final value of the attribute
1818// divisor.
1819TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1820{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001821 if (!requestMultiviewExtension(isMultisampled()))
Martin Radevced5c862017-08-17 16:05:29 +03001822 {
1823 return;
1824 }
1825
Geoff Lang25858162017-11-06 11:25:58 -05001826 // Test failing on P400 graphics card (anglebug.com/2228)
1827 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1828
Olli Etuaho44ae8992018-08-20 15:37:09 +03001829 // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
1830 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001831 if (IsWindows() && IsD3D11())
1832 {
1833 ignoreD3D11SDKLayersWarnings();
1834 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001835
Martin Radevced5c862017-08-17 16:05:29 +03001836 GLVertexArray vao;
1837 glBindVertexArray(vao);
1838 GLBuffer vbo;
1839 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1840 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
1841 Vector2I(3, 0)};
1842 std::vector<Vector2> vertexDataInClipSpace =
1843 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
1844 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
1845 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
1846 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1847 glEnableVertexAttribArray(0);
1848 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
1849 glVertexAttribDivisor(0, 1);
1850 ASSERT_GL_NO_ERROR();
1851
1852 // Create a program and fbo with N views and draw N instances of a point horizontally.
1853 for (int numViews = 2; numViews <= 4; ++numViews)
1854 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001855 updateFBOs(4, 1, numViews);
Martin Radevced5c862017-08-17 16:05:29 +03001856 ASSERT_GL_NO_ERROR();
1857
1858 GLuint program = CreateSimplePassthroughProgram(numViews);
1859 ASSERT_NE(program, 0u);
1860 glUseProgram(program);
1861 ASSERT_GL_NO_ERROR();
1862
1863 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
1864
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001865 resolveMultisampledFBO();
Martin Radevced5c862017-08-17 16:05:29 +03001866 for (int view = 0; view < numViews; ++view)
1867 {
1868 for (int j = 0; j < numViews; ++j)
1869 {
Martin Radev67a8a012017-09-08 13:03:52 +03001870 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03001871 }
1872 for (int j = numViews; j < 4; ++j)
1873 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001874 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03001875 }
1876 }
1877
1878 glDeleteProgram(program);
1879 }
1880}
1881
Martin Radev72b4e1e2017-08-31 15:42:56 +03001882// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
1883TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
1884{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001885 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev72b4e1e2017-08-31 15:42:56 +03001886 {
1887 return;
1888 }
1889
Jamie Madill35cd7332018-12-02 12:03:33 -05001890 constexpr char kVS[] =
Martin Radev72b4e1e2017-08-31 15:42:56 +03001891 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001892 "#extension GL_OVR_multiview2 : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001893 "layout(num_views = 3) in;\n"
1894 "in vec3 vPosition;\n"
1895 "void main()\n"
1896 "{\n"
1897 " gl_Position = vec4(vPosition, 1.);\n"
1898 "}\n";
1899
Jamie Madill35cd7332018-12-02 12:03:33 -05001900 constexpr char kFS[] =
Martin Radev72b4e1e2017-08-31 15:42:56 +03001901 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001902 "#extension GL_OVR_multiview2 : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001903 "precision mediump float;\n"
1904 "out vec4 col;\n"
1905 "void main()\n"
1906 "{\n"
1907 " if (gl_ViewID_OVR == 0u) {\n"
1908 " col = vec4(1,0,0,1);\n"
1909 " } else if (gl_ViewID_OVR == 1u) {\n"
1910 " col = vec4(0,1,0,1);\n"
1911 " } else if (gl_ViewID_OVR == 2u) {\n"
1912 " col = vec4(0,0,1,1);\n"
1913 " } else {\n"
1914 " col = vec4(0,0,0,0);\n"
1915 " }\n"
1916 "}\n";
1917
Olli Etuaho4836acc2018-08-20 15:23:18 +03001918 updateFBOs(1, 1, 3);
Jamie Madill35cd7332018-12-02 12:03:33 -05001919 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev72b4e1e2017-08-31 15:42:56 +03001920
1921 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1922 ASSERT_GL_NO_ERROR();
1923
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001924 resolveMultisampledFBO();
Martin Radev72b4e1e2017-08-31 15:42:56 +03001925 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1926 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1927 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
1928}
1929
1930// The test checks that the inactive layers of a 2D texture array are not written to by a
1931// multi-view program.
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001932TEST_P(MultiviewLayeredRenderTest, RenderToSubrangeOfLayers)
Martin Radev72b4e1e2017-08-31 15:42:56 +03001933{
1934 if (!requestMultiviewExtension())
1935 {
1936 return;
1937 }
1938
Jamie Madill35cd7332018-12-02 12:03:33 -05001939 constexpr char kVS[] =
Martin Radev72b4e1e2017-08-31 15:42:56 +03001940 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001941 "#extension GL_OVR_multiview2 : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001942 "layout(num_views = 2) in;\n"
1943 "in vec3 vPosition;\n"
1944 "void main()\n"
1945 "{\n"
1946 " gl_Position = vec4(vPosition, 1.);\n"
1947 "}\n";
1948
Jamie Madill35cd7332018-12-02 12:03:33 -05001949 constexpr char kFS[] =
Martin Radev72b4e1e2017-08-31 15:42:56 +03001950 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001951 "#extension GL_OVR_multiview2 : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001952 "precision mediump float;\n"
1953 "out vec4 col;\n"
1954 "void main()\n"
1955 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001956 " col = vec4(0,1,0,1);\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001957 "}\n";
1958
Olli Etuaho4836acc2018-08-20 15:23:18 +03001959 updateFBOs(1, 1, 2, 4, 1);
Jamie Madill35cd7332018-12-02 12:03:33 -05001960 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev72b4e1e2017-08-31 15:42:56 +03001961
1962 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1963 ASSERT_GL_NO_ERROR();
1964
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001965 resolveMultisampledFBO();
Martin Radev72b4e1e2017-08-31 15:42:56 +03001966 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +03001967 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1968 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03001969 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
1970}
1971
Martin Radevc1d4e552017-08-21 12:01:10 +03001972// The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
1973// potential bugs if the view is selected in the VS. The test contains a program in which the
1974// gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
1975// fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
1976// never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
1977// green for view 1.
1978TEST_P(MultiviewRenderTest, FlatInterpolation)
Martin Radev3c25ad02017-08-22 17:36:53 +03001979{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001980 if (!requestMultiviewExtension(isMultisampled()))
Martin Radevc1d4e552017-08-21 12:01:10 +03001981 {
1982 return;
1983 }
1984
Jamie Madill35cd7332018-12-02 12:03:33 -05001985 constexpr char kVS[] =
Martin Radevc1d4e552017-08-21 12:01:10 +03001986 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001987 "#extension GL_OVR_multiview2 : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03001988 "layout(num_views = 2) in;\n"
1989 "in vec3 vPosition;\n"
1990 "flat out int oInstanceID;\n"
1991 "void main()\n"
1992 "{\n"
1993 " gl_Position = vec4(vPosition, 1.);\n"
1994 " oInstanceID = gl_InstanceID;\n"
1995 "}\n";
1996
Jamie Madill35cd7332018-12-02 12:03:33 -05001997 constexpr char kFS[] =
Martin Radevc1d4e552017-08-21 12:01:10 +03001998 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001999 "#extension GL_OVR_multiview2 : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002000 "precision mediump float;\n"
2001 "flat in int oInstanceID;\n"
2002 "out vec4 col;\n"
2003 "void main()\n"
2004 "{\n"
2005 " if (oInstanceID < 0) {\n"
2006 " discard;\n"
2007 " }\n"
2008 " if (gl_ViewID_OVR == 0u) {\n"
2009 " col = vec4(1,0,0,1);\n"
2010 " } else {\n"
2011 " col = vec4(0,1,0,1);\n"
2012 " }\n"
2013 "}\n";
2014
Olli Etuaho4836acc2018-08-20 15:23:18 +03002015 updateFBOs(1, 1, 2);
Jamie Madill35cd7332018-12-02 12:03:33 -05002016 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radevc1d4e552017-08-21 12:01:10 +03002017
2018 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2019 ASSERT_GL_NO_ERROR();
2020
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002021 resolveMultisampledFBO();
Martin Radevc1d4e552017-08-21 12:01:10 +03002022 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2023 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +03002024}
2025
Olli Etuaho604d8732018-07-20 11:02:43 +03002026// This test assigns gl_ViewID_OVR to a flat int varying and then sets the color based on that
2027// varying in the fragment shader.
2028TEST_P(MultiviewRenderTest, FlatInterpolation2)
2029{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002030 if (!requestMultiviewExtension(isMultisampled()))
Olli Etuaho604d8732018-07-20 11:02:43 +03002031 {
2032 return;
2033 }
2034
Jamie Madill35cd7332018-12-02 12:03:33 -05002035 constexpr char kVS[] =
Olli Etuaho604d8732018-07-20 11:02:43 +03002036 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07002037 "#extension GL_OVR_multiview2 : require\n"
Olli Etuaho604d8732018-07-20 11:02:43 +03002038 "layout(num_views = 2) in;\n"
2039 "in vec3 vPosition;\n"
2040 "flat out int flatVarying;\n"
2041 "void main()\n"
2042 "{\n"
2043 " gl_Position = vec4(vPosition, 1.);\n"
2044 " flatVarying = int(gl_ViewID_OVR);\n"
2045 "}\n";
2046
Jamie Madill35cd7332018-12-02 12:03:33 -05002047 constexpr char kFS[] =
Olli Etuaho604d8732018-07-20 11:02:43 +03002048 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07002049 "#extension GL_OVR_multiview2 : require\n"
Olli Etuaho604d8732018-07-20 11:02:43 +03002050 "precision mediump float;\n"
2051 "flat in int flatVarying;\n"
2052 "out vec4 col;\n"
2053 "void main()\n"
2054 "{\n"
2055 " if (flatVarying == 0) {\n"
2056 " col = vec4(1,0,0,1);\n"
2057 " } else {\n"
2058 " col = vec4(0,1,0,1);\n"
2059 " }\n"
2060 "}\n";
2061
Olli Etuaho4836acc2018-08-20 15:23:18 +03002062 updateFBOs(1, 1, 2);
Jamie Madill35cd7332018-12-02 12:03:33 -05002063 ANGLE_GL_PROGRAM(program, kVS, kFS);
Olli Etuaho604d8732018-07-20 11:02:43 +03002064
2065 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2066 ASSERT_GL_NO_ERROR();
2067
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002068 resolveMultisampledFBO();
Olli Etuaho604d8732018-07-20 11:02:43 +03002069 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2070 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2071}
2072
Mingyu Hu7d64c482019-03-12 14:27:40 -07002073MultiviewRenderTestParams VertexShaderOpenGL()
Martin Radev265a6d42017-09-12 16:51:37 +03002074{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002075 return MultiviewRenderTestParams(0, VertexShaderOpenGL(3, 0));
Martin Radev265a6d42017-09-12 16:51:37 +03002076}
2077
Mingyu Hu7d64c482019-03-12 14:27:40 -07002078MultiviewRenderTestParams GeomShaderD3D11()
Martin Radev3c25ad02017-08-22 17:36:53 +03002079{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002080 return MultiviewRenderTestParams(0, GeomShaderD3D11(3, 0));
Martin Radev3c25ad02017-08-22 17:36:53 +03002081}
2082
Mingyu Hu7d64c482019-03-12 14:27:40 -07002083MultiviewRenderTestParams VertexShaderD3D11()
Martin Radev3c25ad02017-08-22 17:36:53 +03002084{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002085 return MultiviewRenderTestParams(0, VertexShaderD3D11(3, 0));
Martin Radev3c25ad02017-08-22 17:36:53 +03002086}
2087
Mingyu Hu7d64c482019-03-12 14:27:40 -07002088MultiviewRenderTestParams MultisampledVertexShaderOpenGL()
Martin Radev72b4e1e2017-08-31 15:42:56 +03002089{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002090 return MultiviewRenderTestParams(2, VertexShaderOpenGL(3, 1));
Martin Radevc1d4e552017-08-21 12:01:10 +03002091}
2092
Mingyu Hu7d64c482019-03-12 14:27:40 -07002093MultiviewRenderTestParams MultisampledVertexShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002094{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002095 return MultiviewRenderTestParams(2, VertexShaderD3D11(3, 1));
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002096}
2097
Jamie Madill04c084d2018-08-08 15:49:28 -04002098ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest,
Olli Etuaho44ae8992018-08-20 15:37:09 +03002099 VertexShaderOpenGL(3, 1),
2100 VertexShaderD3D11(3, 1));
Martin Radevced5c862017-08-17 16:05:29 +03002101ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
Mingyu Hu7d64c482019-03-12 14:27:40 -07002102 VertexShaderOpenGL(),
2103 MultisampledVertexShaderOpenGL(),
2104 GeomShaderD3D11(),
2105 VertexShaderD3D11(),
2106 MultisampledVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002107ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
Mingyu Hu7d64c482019-03-12 14:27:40 -07002108 VertexShaderOpenGL(),
2109 MultisampledVertexShaderOpenGL(),
2110 GeomShaderD3D11(),
2111 VertexShaderD3D11(),
2112 MultisampledVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002113ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
Mingyu Hu7d64c482019-03-12 14:27:40 -07002114 VertexShaderOpenGL(),
2115 GeomShaderD3D11(),
2116 VertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002117ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
Olli Etuaho4bcaf992018-08-17 17:18:28 +03002118 VertexShaderOpenGL(3, 0),
2119 GeomShaderD3D11(3, 0),
2120 VertexShaderD3D11(3, 0));
Martin Radevced5c862017-08-17 16:05:29 +03002121ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
Mingyu Hu7d64c482019-03-12 14:27:40 -07002122 VertexShaderOpenGL(),
2123 GeomShaderD3D11(),
2124 VertexShaderD3D11());
Jamie Madill04c084d2018-08-08 15:49:28 -04002125ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, VertexShaderOpenGL(3, 0), GeomShaderD3D11(3, 0));