blob: 3a71ea95c1e532502ce6f3d4547ec64cf5750b44 [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 {
361 if (extensionRequestable("GL_EXT_occlusion_query_boolean"))
362 {
363 glRequestExtensionANGLE("GL_EXT_occlusion_query_boolean");
364 }
365
366 if (!extensionEnabled("GL_EXT_occlusion_query_boolean"))
367 {
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"
465 "void main()\n"
466 "{}\n";
467
Olli Etuaho44ae8992018-08-20 15:37:09 +0300468 GLVertexArray vao;
469 GLBuffer vertexBuffer;
470 GLBuffer indexBuffer;
471 initVAO(vao, vertexBuffer, indexBuffer);
472
473 GLFramebuffer fbo;
474 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
475
Martin Radev14a26ae2017-07-24 15:56:29 +0300476 GLBuffer commandBuffer;
477 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
478 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
479 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
480 ASSERT_GL_NO_ERROR();
481
Mingyu Hu7d64c482019-03-12 14:27:40 -0700482 // Check that no errors are generated with the framebuffer having 2 views.
Martin Radev14a26ae2017-07-24 15:56:29 +0300483 {
Jamie Madill35cd7332018-12-02 12:03:33 -0500484 constexpr char kVS[] =
Martin Radev14a26ae2017-07-24 15:56:29 +0300485 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700486 "#extension GL_OVR_multiview2 : require\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300487 "layout(num_views = 2) in;\n"
488 "void main()\n"
489 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500490 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev14a26ae2017-07-24 15:56:29 +0300491 glUseProgram(program);
492
Mingyu Hu7d64c482019-03-12 14:27:40 -0700493 GLTexture tex2DArray;
494 initOnePixelColorTexture2DMultiLayered(tex2DArray);
495
496 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radev14a26ae2017-07-24 15:56:29 +0300497
498 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700499 EXPECT_GL_NO_ERROR();
Martin Radev14a26ae2017-07-24 15:56:29 +0300500
501 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700502 EXPECT_GL_NO_ERROR();
Martin Radev14a26ae2017-07-24 15:56:29 +0300503 }
504
505 // Check that no errors are generated if the number of views is 1.
506 {
Jamie Madill35cd7332018-12-02 12:03:33 -0500507 constexpr char kVS[] =
Martin Radev14a26ae2017-07-24 15:56:29 +0300508 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700509 "#extension GL_OVR_multiview2 : require\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300510 "layout(num_views = 1) in;\n"
511 "void main()\n"
512 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500513 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev14a26ae2017-07-24 15:56:29 +0300514 glUseProgram(program);
515
Mingyu Hu7d64c482019-03-12 14:27:40 -0700516 GLTexture tex2D;
517 initOnePixelColorTexture2DSingleLayered(tex2D);
518
519 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Martin Radev14a26ae2017-07-24 15:56:29 +0300520
521 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
522 EXPECT_GL_NO_ERROR();
523
524 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
525 EXPECT_GL_NO_ERROR();
526 }
527}
528
Martin Radev7cf61662017-07-26 17:10:53 +0300529// The test verifies that glDraw*:
530// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
531// program differs.
532// 2) does not generate any error if the number of views is the same.
Martin Radev7cf61662017-07-26 17:10:53 +0300533TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
534{
Jamie Madill3a256222018-12-08 09:56:39 -0500535 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radev7cf61662017-07-26 17:10:53 +0300536
Jamie Madill35cd7332018-12-02 12:03:33 -0500537 constexpr char kVS[] =
Martin Radev7cf61662017-07-26 17:10:53 +0300538 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700539 "#extension GL_OVR_multiview2 : require\n"
Martin Radev7cf61662017-07-26 17:10:53 +0300540 "layout(num_views = 2) in;\n"
541 "void main()\n"
542 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500543 constexpr char kFS[] =
Martin Radev7cf61662017-07-26 17:10:53 +0300544 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700545 "#extension GL_OVR_multiview2 : require\n"
Martin Radev7cf61662017-07-26 17:10:53 +0300546 "precision mediump float;\n"
547 "void main()\n"
548 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500549 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev7cf61662017-07-26 17:10:53 +0300550 glUseProgram(program);
551
Olli Etuaho44ae8992018-08-20 15:37:09 +0300552 GLVertexArray vao;
553 GLBuffer vertexBuffer;
554 GLBuffer indexBuffer;
555 initVAO(vao, vertexBuffer, indexBuffer);
556
557 GLFramebuffer fbo;
558 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
559
Martin Radev7cf61662017-07-26 17:10:53 +0300560 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
561 // number of views.
562 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700563 GLTexture tex2D;
564 initOnePixelColorTexture2DSingleLayered(tex2D);
565
Martin Radev7cf61662017-07-26 17:10:53 +0300566 // The framebuffer has only 1 view.
Mingyu Hu7d64c482019-03-12 14:27:40 -0700567 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Martin Radev7cf61662017-07-26 17:10:53 +0300568
569 glDrawArrays(GL_TRIANGLES, 0, 3);
570 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
571
572 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
573 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
574 }
575
576 // Check that no errors are generated if the number of views in both program and draw
577 // framebuffer matches.
578 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700579 GLTexture tex2DArray;
580 initOnePixelColorTexture2DMultiLayered(tex2DArray);
581
582 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radev7cf61662017-07-26 17:10:53 +0300583
584 glDrawArrays(GL_TRIANGLES, 0, 3);
585 EXPECT_GL_NO_ERROR();
586
587 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
588 EXPECT_GL_NO_ERROR();
589 }
Martin Radevda8e2572017-09-12 17:21:16 +0300590}
Martin Radev7cf61662017-07-26 17:10:53 +0300591
Martin Radevda8e2572017-09-12 17:21:16 +0300592// The test verifies that glDraw* generates an INVALID_OPERATION error if the program does not use
593// the multiview extension, but the active draw framebuffer has more than one view.
594TEST_P(MultiviewDrawValidationTest, NumViewsMismatchForNonMultiviewProgram)
595{
596 if (!requestMultiviewExtension())
Martin Radev7cf61662017-07-26 17:10:53 +0300597 {
Martin Radevda8e2572017-09-12 17:21:16 +0300598 return;
Martin Radev7cf61662017-07-26 17:10:53 +0300599 }
Martin Radevda8e2572017-09-12 17:21:16 +0300600
Jamie Madill35cd7332018-12-02 12:03:33 -0500601 constexpr char kVS[] =
Martin Radevda8e2572017-09-12 17:21:16 +0300602 "#version 300 es\n"
603 "void main()\n"
604 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500605 constexpr char kFS[] =
Martin Radevda8e2572017-09-12 17:21:16 +0300606 "#version 300 es\n"
607 "precision mediump float;\n"
608 "void main()\n"
609 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500610 ANGLE_GL_PROGRAM(programNoMultiview, kVS, kFS);
Martin Radevda8e2572017-09-12 17:21:16 +0300611 glUseProgram(programNoMultiview);
612
Olli Etuaho44ae8992018-08-20 15:37:09 +0300613 GLVertexArray vao;
614 GLBuffer vertexBuffer;
615 GLBuffer indexBuffer;
616 initVAO(vao, vertexBuffer, indexBuffer);
617
618 GLFramebuffer fbo;
619 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
620
Mingyu Hu7d64c482019-03-12 14:27:40 -0700621 GLTexture tex2DArray;
622 initOnePixelColorTexture2DMultiLayered(tex2DArray);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300623
Mingyu Hu7d64c482019-03-12 14:27:40 -0700624 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radevda8e2572017-09-12 17:21:16 +0300625
626 glDrawArrays(GL_TRIANGLES, 0, 3);
627 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
628
629 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
630 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radev7cf61662017-07-26 17:10:53 +0300631}
632
Martin Radev7e69f762017-07-27 14:54:13 +0300633// The test verifies that glDraw*:
634// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
Jamie Madill3a256222018-12-08 09:56:39 -0500635// greater than 1 and there is an active not paused transform feedback object.
Martin Radev7e69f762017-07-27 14:54:13 +0300636// 2) does not generate any error if the number of views in the draw framebuffer is 1.
637TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
638{
Jamie Madill3a256222018-12-08 09:56:39 -0500639 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radev7e69f762017-07-27 14:54:13 +0300640
Jamie Madill35cd7332018-12-02 12:03:33 -0500641 constexpr char kVS[] = R"(#version 300 es
642out float tfVarying;
643void main()
644{
645 tfVarying = 1.0;
646})";
647
648 constexpr char kFS[] = R"(#version 300 es
649precision mediump float;
650void main()
651{})";
Jamie Madill04c084d2018-08-08 15:49:28 -0400652
Olli Etuaho3755c482017-10-13 15:40:26 +0300653 std::vector<std::string> tfVaryings;
Jamie Madill04c084d2018-08-08 15:49:28 -0400654 tfVaryings.emplace_back("tfVarying");
Jamie Madill35cd7332018-12-02 12:03:33 -0500655 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(singleViewProgram, kVS, kFS, tfVaryings,
Olli Etuaho3755c482017-10-13 15:40:26 +0300656 GL_SEPARATE_ATTRIBS);
Jamie Madill04c084d2018-08-08 15:49:28 -0400657
658 std::vector<std::string> dualViewTFVaryings;
659 dualViewTFVaryings.emplace_back("gl_Position");
660 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(dualViewProgram, kDualViewVSSource, kDualViewFSSource,
661 dualViewTFVaryings, GL_SEPARATE_ATTRIBS);
Martin Radev7e69f762017-07-27 14:54:13 +0300662
Olli Etuaho44ae8992018-08-20 15:37:09 +0300663 GLVertexArray vao;
664 GLBuffer vertexBuffer;
665 GLBuffer indexBuffer;
666 initVAO(vao, vertexBuffer, indexBuffer);
667
Martin Radev7e69f762017-07-27 14:54:13 +0300668 GLBuffer tbo;
669 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
Jamie Madill04c084d2018-08-08 15:49:28 -0400670 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 16u, nullptr, GL_STATIC_DRAW);
Martin Radev7e69f762017-07-27 14:54:13 +0300671
672 GLTransformFeedback transformFeedback;
673 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
Olli Etuaho3755c482017-10-13 15:40:26 +0300674
675 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
676
Jamie Madill04c084d2018-08-08 15:49:28 -0400677 glUseProgram(dualViewProgram);
Martin Radev7e69f762017-07-27 14:54:13 +0300678 glBeginTransformFeedback(GL_TRIANGLES);
679 ASSERT_GL_NO_ERROR();
680
Olli Etuaho44ae8992018-08-20 15:37:09 +0300681 GLFramebuffer fbo;
682 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
683
Mingyu Hu7d64c482019-03-12 14:27:40 -0700684 GLTexture tex2DArray;
685 initOnePixelColorTexture2DMultiLayered(tex2DArray);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300686
Martin Radev7e69f762017-07-27 14:54:13 +0300687 // Check that drawArrays generates an error when there is an active transform feedback object
688 // and the number of views in the draw framebuffer is greater than 1.
689 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700690 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radev7e69f762017-07-27 14:54:13 +0300691 glDrawArrays(GL_TRIANGLES, 0, 3);
692 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
693 }
694
Jamie Madill04c084d2018-08-08 15:49:28 -0400695 glEndTransformFeedback();
696
697 // Ending transform feedback should allow the draw to succeed.
698 {
699 glDrawArrays(GL_TRIANGLES, 0, 3);
700 EXPECT_GL_NO_ERROR();
701 }
702
Jamie Madill3a256222018-12-08 09:56:39 -0500703 // A paused transform feedback should not trigger an error.
Jamie Madill04c084d2018-08-08 15:49:28 -0400704 glBeginTransformFeedback(GL_TRIANGLES);
705 glPauseTransformFeedback();
706 ASSERT_GL_NO_ERROR();
707
708 glDrawArrays(GL_TRIANGLES, 0, 3);
Jamie Madill3a256222018-12-08 09:56:39 -0500709 ASSERT_GL_NO_ERROR();
Jamie Madill04c084d2018-08-08 15:49:28 -0400710
711 // Unbind transform feedback - should succeed.
712 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
713 glDrawArrays(GL_TRIANGLES, 0, 3);
714 ASSERT_GL_NO_ERROR();
715
Jamie Madill3a256222018-12-08 09:56:39 -0500716 // Rebind paused transform feedback - should succeed.
Jamie Madill04c084d2018-08-08 15:49:28 -0400717 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
718 glDrawArrays(GL_TRIANGLES, 0, 3);
Jamie Madill3a256222018-12-08 09:56:39 -0500719 ASSERT_GL_NO_ERROR();
Jamie Madill04c084d2018-08-08 15:49:28 -0400720
721 glResumeTransformFeedback();
722 glEndTransformFeedback();
723
724 glUseProgram(singleViewProgram);
725 glBeginTransformFeedback(GL_TRIANGLES);
726 ASSERT_GL_NO_ERROR();
727
Mingyu Hu7d64c482019-03-12 14:27:40 -0700728 GLTexture tex2D;
729 initOnePixelColorTexture2DSingleLayered(tex2D);
730
Martin Radev7e69f762017-07-27 14:54:13 +0300731 // Check that drawArrays does not generate an error when the number of views in the draw
732 // framebuffer is 1.
733 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700734 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Martin Radev7e69f762017-07-27 14:54:13 +0300735 glDrawArrays(GL_TRIANGLES, 0, 3);
736 EXPECT_GL_NO_ERROR();
737 }
738
739 glEndTransformFeedback();
740}
741
Martin Radevffe754b2017-07-31 10:38:07 +0300742// The test verifies that glDraw*:
743// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
744// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
745// 2) does not generate any error if the number of views in the draw framebuffer is 1.
746TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
747{
Yunchao He9550c602018-02-13 14:47:05 +0800748 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Jamie Madill3a256222018-12-08 09:56:39 -0500749 ANGLE_SKIP_TEST_IF(!ensureExtensionEnabled("GL_EXT_disjoint_timer_query"));
Martin Radevffe754b2017-07-31 10:38:07 +0300750
Olli Etuaho44ae8992018-08-20 15:37:09 +0300751 ANGLE_GL_PROGRAM(dualViewProgram, kDualViewVSSource, kDualViewFSSource);
752
Jamie Madill35cd7332018-12-02 12:03:33 -0500753 constexpr char kVS[] =
Martin Radevffe754b2017-07-31 10:38:07 +0300754 "#version 300 es\n"
755 "void main()\n"
756 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500757 constexpr char kFS[] =
Martin Radevffe754b2017-07-31 10:38:07 +0300758 "#version 300 es\n"
759 "precision mediump float;\n"
760 "void main()\n"
761 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500762 ANGLE_GL_PROGRAM(singleViewProgram, kVS, kFS);
Jamie Madill04c084d2018-08-08 15:49:28 -0400763 glUseProgram(singleViewProgram);
Martin Radevffe754b2017-07-31 10:38:07 +0300764
Olli Etuaho44ae8992018-08-20 15:37:09 +0300765 GLVertexArray vao;
766 GLBuffer vertexBuffer;
767 GLBuffer indexBuffer;
768 initVAO(vao, vertexBuffer, indexBuffer);
769
Martin Radevffe754b2017-07-31 10:38:07 +0300770 GLuint query = 0u;
771 glGenQueriesEXT(1, &query);
772 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
773
Olli Etuaho44ae8992018-08-20 15:37:09 +0300774 GLFramebuffer fbo;
775 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
776
Mingyu Hu7d64c482019-03-12 14:27:40 -0700777 GLTexture tex2DArr;
778 initOnePixelColorTexture2DMultiLayered(tex2DArr);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300779
Martin Radevffe754b2017-07-31 10:38:07 +0300780 // Check first case.
781 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300782 glUseProgram(dualViewProgram);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700783 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArr, 0, 0, 2);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300784 glClear(GL_COLOR_BUFFER_BIT);
785 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radevffe754b2017-07-31 10:38:07 +0300786 glDrawArrays(GL_TRIANGLES, 0, 3);
787 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
788 }
789
Mingyu Hu7d64c482019-03-12 14:27:40 -0700790 GLTexture tex2D;
791 initOnePixelColorTexture2DSingleLayered(tex2D);
792
Martin Radevffe754b2017-07-31 10:38:07 +0300793 // Check second case.
794 {
Jamie Madill04c084d2018-08-08 15:49:28 -0400795 glUseProgram(singleViewProgram);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700796 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300797 glClear(GL_COLOR_BUFFER_BIT);
798 EXPECT_GL_NO_ERROR();
Martin Radevffe754b2017-07-31 10:38:07 +0300799 glDrawArrays(GL_TRIANGLES, 0, 3);
800 EXPECT_GL_NO_ERROR();
801 }
802
803 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
804 glDeleteQueries(1, &query);
Jamie Madill04c084d2018-08-08 15:49:28 -0400805
806 // Check starting a query after a successful draw.
807 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300808 glUseProgram(dualViewProgram);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700809 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArr, 0, 0, 2);
Jamie Madill04c084d2018-08-08 15:49:28 -0400810 glClear(GL_COLOR_BUFFER_BIT);
811 EXPECT_GL_NO_ERROR();
812 glDrawArrays(GL_TRIANGLES, 0, 3);
813 EXPECT_GL_NO_ERROR();
814
815 glGenQueriesEXT(1, &query);
816 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
817
818 glDrawArrays(GL_TRIANGLES, 0, 3);
819 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
820
821 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
822 glDrawArrays(GL_TRIANGLES, 0, 3);
823 EXPECT_GL_NO_ERROR();
824
825 glDeleteQueries(1, &query);
826 }
Martin Radevffe754b2017-07-31 10:38:07 +0300827}
828
Martin Radev8f276e22017-05-30 12:05:52 +0300829// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300830TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300831{
Jamie Madill3a256222018-12-08 09:56:39 -0500832 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
833
Martin Radev8f276e22017-05-30 12:05:52 +0300834 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
835 ASSERT_GL_NO_ERROR();
836
837 checkOutput();
838}
839
840// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300841TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300842{
Jamie Madill3a256222018-12-08 09:56:39 -0500843 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
844
Martin Radev8f276e22017-05-30 12:05:52 +0300845 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
846 ASSERT_GL_NO_ERROR();
847
848 checkOutput();
849}
850
851// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300852TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300853{
Jamie Madill3a256222018-12-08 09:56:39 -0500854 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
855
Martin Radev8f276e22017-05-30 12:05:52 +0300856 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
857 ASSERT_GL_NO_ERROR();
858
859 checkOutput();
860}
861
862// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300863TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300864{
Jamie Madill3a256222018-12-08 09:56:39 -0500865 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev8f276e22017-05-30 12:05:52 +0300866
Jamie Madill35cd7332018-12-02 12:03:33 -0500867 constexpr char kVS[] =
Martin Radev8f276e22017-05-30 12:05:52 +0300868 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700869 "#extension GL_OVR_multiview2 : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300870 "layout(num_views = 4) in;\n"
871 "in vec4 vPosition;\n"
872 "void main()\n"
873 "{\n"
874 " if (gl_ViewID_OVR == 0u) {\n"
875 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
876 " } else if (gl_ViewID_OVR == 1u) {\n"
877 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
878 " } else if (gl_ViewID_OVR == 2u) {\n"
879 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
880 " } else {\n"
881 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
882 " }"
883 " gl_Position.yzw = vPosition.yzw;\n"
884 "}\n";
885
Jamie Madill35cd7332018-12-02 12:03:33 -0500886 constexpr char kFS[] =
Martin Radev8f276e22017-05-30 12:05:52 +0300887 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700888 "#extension GL_OVR_multiview2 : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300889 "precision mediump float;\n"
890 "out vec4 col;\n"
891 "void main()\n"
892 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300893 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300894 "}\n";
895
Olli Etuaho4836acc2018-08-20 15:23:18 +0300896 updateFBOs(4, 1, 4);
Jamie Madill35cd7332018-12-02 12:03:33 -0500897 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev8f276e22017-05-30 12:05:52 +0300898
899 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
900 ASSERT_GL_NO_ERROR();
901
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300902 resolveMultisampledFBO();
Martin Radev8f276e22017-05-30 12:05:52 +0300903 for (int i = 0; i < 4; ++i)
904 {
905 for (int j = 0; j < 4; ++j)
906 {
Martin Radev8f276e22017-05-30 12:05:52 +0300907 if (i == j)
908 {
Martin Radev67a8a012017-09-08 13:03:52 +0300909 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300910 }
911 else
912 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300913 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300914 }
915 }
916 }
917 EXPECT_GL_NO_ERROR();
918}
919
920// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300921TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +0300922{
Jamie Madill3a256222018-12-08 09:56:39 -0500923 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev8f276e22017-05-30 12:05:52 +0300924
Jamie Madill35cd7332018-12-02 12:03:33 -0500925 constexpr char kVS[] =
Martin Radev8f276e22017-05-30 12:05:52 +0300926 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700927 "#extension GL_OVR_multiview2 : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300928 "layout(num_views = 2) in;\n"
929 "in vec4 vPosition;\n"
930 "void main()\n"
931 "{\n"
932 " vec4 p = vPosition;\n"
933 " if (gl_InstanceID == 1){\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300934 " p.y = p.y * 0.5 + 0.5;\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300935 " } else {\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300936 " p.y = p.y * 0.5 - 0.5;\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300937 " }\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300938 " 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 +0300939 " gl_Position.yzw = p.yzw;\n"
940 "}\n";
941
Jamie Madill35cd7332018-12-02 12:03:33 -0500942 constexpr char kFS[] =
Martin Radev8f276e22017-05-30 12:05:52 +0300943 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -0700944 "#extension GL_OVR_multiview2 : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300945 "precision mediump float;\n"
946 "out vec4 col;\n"
947 "void main()\n"
948 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300949 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300950 "}\n";
951
Martin Radev3c25ad02017-08-22 17:36:53 +0300952 const int kViewWidth = 2;
953 const int kViewHeight = 2;
954 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300955 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Jamie Madill35cd7332018-12-02 12:03:33 -0500956 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev8f276e22017-05-30 12:05:52 +0300957
Martin Radev67a8a012017-09-08 13:03:52 +0300958 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 2u);
Martin Radev8f276e22017-05-30 12:05:52 +0300959 ASSERT_GL_NO_ERROR();
960
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300961 resolveMultisampledFBO();
962
Martin Radev67a8a012017-09-08 13:03:52 +0300963 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
964 {{255, 0}, {255, 0}}};
Martin Radev3c25ad02017-08-22 17:36:53 +0300965
966 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +0300967 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300968 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +0300969 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300970 for (int x = 0; x < 2; ++x)
971 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300972 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][y][x], 0,
973 expectedGreenChannel[view][y][x]),
Martin Radev3c25ad02017-08-22 17:36:53 +0300974 GetViewColor(x, y, view));
975 }
Martin Radev8f276e22017-05-30 12:05:52 +0300976 }
977 }
978}
979
Martin Radev553590a2017-07-31 16:40:39 +0300980// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
981// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
982// offset of each quad are passed as separate attributes which are indexed based on the
983// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
984// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
985// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
986// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +0300987TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +0300988{
Jamie Madill3a256222018-12-08 09:56:39 -0500989 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev553590a2017-07-31 16:40:39 +0300990
Corentin Wallez02cd1522018-08-22 13:46:21 +0200991 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +0300992 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +0300993 if (IsWindows() && IsD3D11())
994 {
995 ignoreD3D11SDKLayersWarnings();
996 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300997
Jamie Madill35cd7332018-12-02 12:03:33 -0500998 constexpr char kVS[] =
Martin Radev553590a2017-07-31 16:40:39 +0300999 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001000 "#extension GL_OVR_multiview2 : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001001 "layout(num_views = 2) in;\n"
1002 "in vec3 vPosition;\n"
1003 "in float offsetX;\n"
1004 "in float offsetY;\n"
1005 "void main()\n"
1006 "{\n"
1007 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001008 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001009 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
1010 " gl_Position.yzw = p.yzw;\n"
1011 "}\n";
1012
Jamie Madill35cd7332018-12-02 12:03:33 -05001013 constexpr char kFS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001014 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001015 "#extension GL_OVR_multiview2 : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001016 "precision mediump float;\n"
1017 "out vec4 col;\n"
1018 "void main()\n"
1019 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001020 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001021 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +03001022
1023 const int kViewWidth = 4;
1024 const int kViewHeight = 4;
1025 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001026 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Jamie Madill35cd7332018-12-02 12:03:33 -05001027 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev553590a2017-07-31 16:40:39 +03001028
1029 GLBuffer xOffsetVBO;
1030 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1031 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
1032 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
1033 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1034 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1035 glVertexAttribDivisor(xOffsetLoc, 3);
1036 glEnableVertexAttribArray(xOffsetLoc);
1037
1038 GLBuffer yOffsetVBO;
1039 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1040 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1041 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1042 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1043 glVertexAttribDivisor(yOffsetLoc, 1);
1044 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1045 glEnableVertexAttribArray(yOffsetLoc);
1046
Martin Radev67a8a012017-09-08 13:03:52 +03001047 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev553590a2017-07-31 16:40:39 +03001048 ASSERT_GL_NO_ERROR();
1049
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001050 resolveMultisampledFBO();
1051
Martin Radev67a8a012017-09-08 13:03:52 +03001052 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001053 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1054 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1055 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +03001056 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001057 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +03001058 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001059 for (int col = 0; col < 4; ++col)
1060 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001061 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0,
1062 expectedGreenChannel[view][row][col]),
Martin Radev3c25ad02017-08-22 17:36:53 +03001063 GetViewColor(col, row, view));
1064 }
Martin Radev553590a2017-07-31 16:40:39 +03001065 }
1066 }
1067}
1068
1069// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1070// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +03001071TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +03001072{
Jamie Madill3a256222018-12-08 09:56:39 -05001073 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev553590a2017-07-31 16:40:39 +03001074
Olli Etuaho4836acc2018-08-20 15:23:18 +03001075 updateFBOs(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +03001076
1077 // Create multiview program.
Jamie Madill35cd7332018-12-02 12:03:33 -05001078 constexpr char kVS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001079 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001080 "#extension GL_OVR_multiview2 : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001081 "layout(num_views = 2) in;\n"
1082 "layout(location = 0) in vec2 vPosition;\n"
1083 "layout(location = 1) in float offsetX;\n"
1084 "void main()\n"
1085 "{\n"
1086 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1087 " p.x += offsetX;\n"
1088 " gl_Position = p;\n"
1089 "}\n";
1090
Jamie Madill35cd7332018-12-02 12:03:33 -05001091 constexpr char kFS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001092 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001093 "#extension GL_OVR_multiview2 : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001094 "precision mediump float;\n"
1095 "out vec4 col;\n"
1096 "void main()\n"
1097 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001098 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001099 "}\n";
1100
Jamie Madill35cd7332018-12-02 12:03:33 -05001101 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev553590a2017-07-31 16:40:39 +03001102
Jamie Madill35cd7332018-12-02 12:03:33 -05001103 constexpr char kDummyVS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001104 "#version 300 es\n"
1105 "layout(location = 0) in vec2 vPosition;\n"
1106 "layout(location = 1) in float offsetX;\n"
1107 "void main()\n"
1108 "{\n"
1109 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1110 "}\n";
1111
Jamie Madill35cd7332018-12-02 12:03:33 -05001112 constexpr char kDummyFS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001113 "#version 300 es\n"
1114 "precision mediump float;\n"
1115 "out vec4 col;\n"
1116 "void main()\n"
1117 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001118 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001119 "}\n";
1120
Jamie Madill35cd7332018-12-02 12:03:33 -05001121 ANGLE_GL_PROGRAM(dummyProgram, kDummyVS, kDummyFS);
Martin Radev553590a2017-07-31 16:40:39 +03001122
1123 GLBuffer xOffsetVBO;
1124 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1125 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1126 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1127 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1128
1129 GLBuffer vertexVBO;
1130 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1131 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1132 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1133 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1134
1135 GLVertexArray vao[2];
1136 for (size_t i = 0u; i < 2u; ++i)
1137 {
1138 glBindVertexArray(vao[i]);
1139
1140 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1141 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1142 glEnableVertexAttribArray(0);
1143
1144 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1145 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1146 glEnableVertexAttribArray(1);
1147 }
1148 ASSERT_GL_NO_ERROR();
1149
1150 glViewport(0, 0, 1, 1);
1151 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001152 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001153 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001154
1155 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1156 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1157 // bits are cleared.
1158 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001159 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1160 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001161 glBindVertexArray(vao[0]);
1162 glVertexAttribDivisor(1, 0);
1163 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1164 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001165 ASSERT_GL_NO_ERROR();
1166
1167 // Check that vertexAttribDivisor uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001168 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001169 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001170 glUseProgram(program);
1171 glVertexAttribDivisor(1, 1);
1172 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001173
1174 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001175 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1176 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001177
1178 // Clear the buffers and propagate divisor to the driver.
1179 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1180 // dirty bits when useProgram is called.
1181 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001182 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1183 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001184 glVertexAttribDivisor(1, 1);
1185 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1186 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001187 ASSERT_GL_NO_ERROR();
1188
1189 // Check that useProgram uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001190 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001191 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001192 glUseProgram(program);
1193 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001194
1195 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001196 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1197 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001198
1199 // We go through similar steps as before.
1200 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001201 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1202 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001203 glVertexAttribDivisor(1, 1);
1204 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1205 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001206 ASSERT_GL_NO_ERROR();
1207
1208 // Check that bindVertexArray uses the number of views to update the divisor.
1209 {
1210 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1211 // divisor for vao[1] only.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001212 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001213 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001214 glBindVertexArray(vao[1]);
1215 glUseProgram(program);
1216 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001217 glBindVertexArray(0);
1218 ASSERT_GL_NO_ERROR();
1219 }
1220 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1221 // adjusts the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001222 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001223 glBindVertexArray(vao[0]);
1224 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001225
1226 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001227 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1228 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001229}
1230
Martin Radev0d671c92017-08-10 16:41:52 +03001231// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1232// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001233TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001234{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001235 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1236 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001237
Jamie Madill35cd7332018-12-02 12:03:33 -05001238 constexpr char kVS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001239 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001240 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001241 "layout(num_views = 2) in;\n"
1242 "in vec3 vPosition;\n"
1243 "void main()\n"
1244 "{\n"
1245 " gl_Position.x = 2.0;\n"
1246 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1247 "}\n";
1248
Jamie Madill35cd7332018-12-02 12:03:33 -05001249 constexpr char kFS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001250 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001251 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001252 "precision mediump float;\n"
1253 "out vec4 col;\n"
1254 "void main()\n"
1255 "{\n"
1256 " col = vec4(1,0,0,0);\n"
1257 "}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -05001258 ANGLE_GL_PROGRAM(program, kVS, kFS);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001259 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001260
1261 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1262 ASSERT_GL_NO_ERROR();
1263 EXPECT_GL_FALSE(result);
1264}
1265
1266// Test that there are fragments passing the occlusion query if only view 0 can produce
1267// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001268TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001269{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001270 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1271 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001272
Jamie Madill35cd7332018-12-02 12:03:33 -05001273 constexpr char kVS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001274 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001275 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001276 "layout(num_views = 2) in;\n"
1277 "in vec3 vPosition;\n"
1278 "void main()\n"
1279 "{\n"
1280 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1281 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1282 "}\n";
1283
Jamie Madill35cd7332018-12-02 12:03:33 -05001284 constexpr char kFS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001285 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001286 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001287 "precision mediump float;\n"
1288 "out vec4 col;\n"
1289 "void main()\n"
1290 "{\n"
1291 " col = vec4(1,0,0,0);\n"
1292 "}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -05001293 ANGLE_GL_PROGRAM(program, kVS, kFS);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001294 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001295
1296 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1297 ASSERT_GL_NO_ERROR();
1298 EXPECT_GL_TRUE(result);
1299}
1300
1301// Test that there are fragments passing the occlusion query if only view 1 can produce
1302// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001303TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001304{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001305 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1306 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001307
Jamie Madill35cd7332018-12-02 12:03:33 -05001308 constexpr char kVS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001309 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001310 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001311 "layout(num_views = 2) in;\n"
1312 "in vec3 vPosition;\n"
1313 "void main()\n"
1314 "{\n"
1315 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1316 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1317 "}\n";
1318
Jamie Madill35cd7332018-12-02 12:03:33 -05001319 constexpr char kFS[] =
Martin Radev0d671c92017-08-10 16:41:52 +03001320 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001321 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001322 "precision mediump float;\n"
1323 "out vec4 col;\n"
1324 "void main()\n"
1325 "{\n"
1326 " col = vec4(1,0,0,0);\n"
1327 "}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -05001328 ANGLE_GL_PROGRAM(program, kVS, kFS);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001329 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001330
1331 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1332 ASSERT_GL_NO_ERROR();
1333 EXPECT_GL_TRUE(result);
1334}
1335
Martin Radev41ac68e2017-06-06 12:16:58 +03001336// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1337// compiles and links without an error.
1338TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1339{
1340 if (!requestMultiviewExtension())
1341 {
1342 return;
1343 }
1344
Jamie Madill35cd7332018-12-02 12:03:33 -05001345 constexpr char kVS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001346 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001347 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001348 "layout(num_views = 2) in;\n"
1349 "void main()\n"
1350 "{\n"
1351 "}\n";
1352
Jamie Madill35cd7332018-12-02 12:03:33 -05001353 constexpr char kFS[] =
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 "precision mediump float;\n"
1357 "void main()\n"
1358 "{\n"
1359 "}\n";
1360
Jamie Madill35cd7332018-12-02 12:03:33 -05001361 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev41ac68e2017-06-06 12:16:58 +03001362 glUseProgram(program);
1363
1364 EXPECT_GL_NO_ERROR();
1365}
1366
1367// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1368// without an error.
1369TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1370{
1371 if (!requestMultiviewExtension())
1372 {
1373 return;
1374 }
1375
Jamie Madill35cd7332018-12-02 12:03:33 -05001376 constexpr char kVS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001377 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001378 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001379 "layout(num_views = 2) in;\n"
1380 "void main()\n"
1381 "{\n"
1382 " if (gl_ViewID_OVR == 0u) {\n"
1383 " gl_Position = vec4(1,0,0,1);\n"
1384 " } else {\n"
1385 " gl_Position = vec4(-1,0,0,1);\n"
1386 " }\n"
1387 "}\n";
1388
Jamie Madill35cd7332018-12-02 12:03:33 -05001389 constexpr char kFS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001390 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001391 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001392 "precision mediump float;\n"
1393 "void main()\n"
1394 "{\n"
1395 "}\n";
1396
Jamie Madill35cd7332018-12-02 12:03:33 -05001397 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev41ac68e2017-06-06 12:16:58 +03001398 glUseProgram(program);
1399
1400 EXPECT_GL_NO_ERROR();
1401}
1402
1403// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1404// without an error.
1405TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1406{
1407 if (!requestMultiviewExtension())
1408 {
1409 return;
1410 }
1411
Jamie Madill35cd7332018-12-02 12:03:33 -05001412 constexpr char kVS[] =
Martin Radev41ac68e2017-06-06 12:16:58 +03001413 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001414 "#extension GL_OVR_multiview2 : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001415 "layout(num_views = 2) in;\n"
1416 "void main()\n"
1417 "{\n"
1418 "}\n";
1419
Jamie Madill35cd7332018-12-02 12:03:33 -05001420 constexpr char kFS[] =
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 "precision mediump float;\n"
1424 "out vec4 col;\n"
1425 "void main()\n"
1426 "{\n"
1427 " if (gl_ViewID_OVR == 0u) {\n"
1428 " col = vec4(1,0,0,1);\n"
1429 " } else {\n"
1430 " col = vec4(-1,0,0,1);\n"
1431 " }\n"
1432 "}\n";
1433
Jamie Madill35cd7332018-12-02 12:03:33 -05001434 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev41ac68e2017-06-06 12:16:58 +03001435 glUseProgram(program);
1436
1437 EXPECT_GL_NO_ERROR();
1438}
1439
Martin Radev61bd9992017-08-11 13:10:55 +03001440// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001441TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001442{
1443 if (!requestMultiviewExtension())
1444 {
1445 return;
1446 }
1447
Geoff Lang25858162017-11-06 11:25:58 -05001448 // Test failing on P400 graphics card (anglebug.com/2228)
1449 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1450
Jamie Madill35cd7332018-12-02 12:03:33 -05001451 constexpr char kVS[] =
Martin Radev61bd9992017-08-11 13:10:55 +03001452 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001453 "#extension GL_OVR_multiview2 : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001454 "layout(num_views = 2) in;\n"
1455 "layout(location=0) in vec2 vPosition;\n"
1456 "void main()\n"
1457 "{\n"
1458 " gl_PointSize = 1.0;\n"
1459 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1460 "}\n";
1461
Jamie Madill35cd7332018-12-02 12:03:33 -05001462 constexpr char kFS[] =
Martin Radev61bd9992017-08-11 13:10:55 +03001463 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001464 "#extension GL_OVR_multiview2 : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001465 "precision mediump float;\n"
1466 "out vec4 col;\n"
1467 "void main()\n"
1468 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001469 " col = vec4(0,1,0,1);\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001470 "}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -05001471 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev61bd9992017-08-11 13:10:55 +03001472 glUseProgram(program);
1473
Martin Radev3c25ad02017-08-22 17:36:53 +03001474 const int kViewWidth = 4;
1475 const int kViewHeight = 2;
1476 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001477 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001478
1479 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1480 std::vector<Vector2> vertexDataInClipSpace =
1481 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1482 setupGeometry(vertexDataInClipSpace);
1483
1484 glDrawArrays(GL_POINTS, 0, 2);
1485
Martin Radev67a8a012017-09-08 13:03:52 +03001486 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001487 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001488 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001489}
1490
1491// The test checks that GL_LINES is correctly rendered.
1492// The behavior of this test is not guaranteed by the spec:
1493// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1494// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1495// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1496// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001497TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001498{
1499 if (!requestMultiviewExtension())
1500 {
1501 return;
1502 }
1503
Martin Radevced5c862017-08-17 16:05:29 +03001504 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001505 ASSERT_NE(program, 0u);
1506 glUseProgram(program);
1507 ASSERT_GL_NO_ERROR();
1508
Martin Radev3c25ad02017-08-22 17:36:53 +03001509 const int kViewWidth = 4;
1510 const int kViewHeight = 2;
1511 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001512 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001513
1514 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1515 std::vector<Vector2> vertexDataInClipSpace =
1516 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1517 setupGeometry(vertexDataInClipSpace);
1518
1519 glDrawArrays(GL_LINES, 0, 2);
1520
Martin Radev67a8a012017-09-08 13:03:52 +03001521 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001522 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001523 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001524
1525 glDeleteProgram(program);
1526}
1527
1528// The test checks that GL_LINE_STRIP is correctly rendered.
1529// The behavior of this test is not guaranteed by the spec:
1530// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1531// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1532// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1533// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001534TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001535{
1536 if (!requestMultiviewExtension())
1537 {
1538 return;
1539 }
1540
Martin Radevced5c862017-08-17 16:05:29 +03001541 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001542 ASSERT_NE(program, 0u);
1543 glUseProgram(program);
1544 ASSERT_GL_NO_ERROR();
1545
Martin Radev3c25ad02017-08-22 17:36:53 +03001546 const int kViewWidth = 4;
1547 const int kViewHeight = 2;
1548 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001549 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001550
1551 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1552 std::vector<Vector2> vertexDataInClipSpace =
1553 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1554 setupGeometry(vertexDataInClipSpace);
1555
1556 glDrawArrays(GL_LINE_STRIP, 0, 3);
1557
Martin Radev67a8a012017-09-08 13:03:52 +03001558 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001559 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001560 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001561
1562 glDeleteProgram(program);
1563}
1564
1565// The test checks that GL_LINE_LOOP is correctly rendered.
1566// The behavior of this test is not guaranteed by the spec:
1567// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1568// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1569// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1570// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001571TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001572{
1573 if (!requestMultiviewExtension())
1574 {
1575 return;
1576 }
1577
Martin Radevced5c862017-08-17 16:05:29 +03001578 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001579 ASSERT_NE(program, 0u);
1580 glUseProgram(program);
1581 ASSERT_GL_NO_ERROR();
1582
Martin Radev3c25ad02017-08-22 17:36:53 +03001583 const int kViewWidth = 4;
1584 const int kViewHeight = 4;
1585 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001586 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001587
1588 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1589 Vector2I(0, 3)};
1590 std::vector<Vector2> vertexDataInClipSpace =
1591 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1592 setupGeometry(vertexDataInClipSpace);
1593
1594 glDrawArrays(GL_LINE_LOOP, 0, 4);
1595
Martin Radev67a8a012017-09-08 13:03:52 +03001596 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001597 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1598 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001599 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001600
1601 glDeleteProgram(program);
1602}
1603
1604// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001605TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001606{
1607 if (!requestMultiviewExtension())
1608 {
1609 return;
1610 }
1611
Martin Radevced5c862017-08-17 16:05:29 +03001612 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001613 ASSERT_NE(program, 0u);
1614 glUseProgram(program);
1615 ASSERT_GL_NO_ERROR();
1616
1617 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1618 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1619 setupGeometry(vertexDataInClipSpace);
1620
Martin Radev3c25ad02017-08-22 17:36:53 +03001621 const int kViewWidth = 2;
1622 const int kViewHeight = 2;
1623 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001624 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001625
1626 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1627
Martin Radev67a8a012017-09-08 13:03:52 +03001628 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1629 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1630 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001631
1632 glDeleteProgram(program);
1633}
1634
1635// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001636TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001637{
1638 if (!requestMultiviewExtension())
1639 {
1640 return;
1641 }
1642
Martin Radevced5c862017-08-17 16:05:29 +03001643 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001644 ASSERT_NE(program, 0u);
1645 glUseProgram(program);
1646 ASSERT_GL_NO_ERROR();
1647
1648 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1649 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1650 setupGeometry(vertexDataInClipSpace);
1651
Martin Radev3c25ad02017-08-22 17:36:53 +03001652 const int kViewWidth = 2;
1653 const int kViewHeight = 2;
1654 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001655 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001656
1657 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1658
Martin Radev67a8a012017-09-08 13:03:52 +03001659 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1660 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1661 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001662
1663 glDeleteProgram(program);
1664}
1665
Martin Radev0abb7a22017-08-28 15:34:45 +03001666// Verify that re-linking a program adjusts the attribute divisor.
1667// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1668// to each other. The quads' position and color depend on the corresponding attribute divisors.
1669TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1670{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001671 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev0abb7a22017-08-28 15:34:45 +03001672 {
1673 return;
1674 }
1675
Corentin Wallez02cd1522018-08-22 13:46:21 +02001676 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001677 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001678 if (IsWindows() && IsD3D11())
1679 {
1680 ignoreD3D11SDKLayersWarnings();
1681 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001682
Martin Radev0abb7a22017-08-28 15:34:45 +03001683 const int kViewWidth = 4;
1684 const int kViewHeight = 1;
1685 const int kNumViews = 2;
1686
Jamie Madill35cd7332018-12-02 12:03:33 -05001687 constexpr char kFS[] =
Martin Radev0abb7a22017-08-28 15:34:45 +03001688 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001689 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001690 "precision mediump float;\n"
1691 "in vec4 oColor;\n"
1692 "out vec4 col;\n"
1693 "void main()\n"
1694 "{\n"
1695 " col = oColor;\n"
1696 "}\n";
1697
1698 auto generateVertexShaderSource = [](int numViews) -> std::string {
1699 std::string source =
1700 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001701 "#extension GL_OVR_multiview2 : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001702 "layout(num_views = " +
1703 ToString(numViews) +
1704 ") in;\n"
1705 "in vec3 vPosition;\n"
1706 "in float vOffsetX;\n"
1707 "in vec4 vColor;\n"
1708 "out vec4 oColor;\n"
1709 "void main()\n"
1710 "{\n"
1711 " vec4 p = vec4(vPosition, 1.);\n"
1712 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1713 " oColor = vColor;\n"
1714 " gl_Position = p;\n"
1715 "}\n";
1716 return source;
1717 };
1718
1719 std::string vsSource = generateVertexShaderSource(kNumViews);
Jamie Madill35cd7332018-12-02 12:03:33 -05001720 ANGLE_GL_PROGRAM(program, vsSource.c_str(), kFS);
Martin Radev0abb7a22017-08-28 15:34:45 +03001721 glUseProgram(program);
1722
1723 GLint positionLoc;
1724 GLBuffer xOffsetVBO;
1725 GLint xOffsetLoc;
1726 GLBuffer colorVBO;
1727 GLint colorLoc;
1728
1729 {
1730 // Initialize buffers and setup attributes.
1731 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1732 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1733 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1734 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1735 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1736 glVertexAttribDivisor(xOffsetLoc, 1);
1737 glEnableVertexAttribArray(xOffsetLoc);
1738
1739 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1740 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1741 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1742 colorLoc = glGetAttribLocation(program, "vColor");
1743 glVertexAttribDivisor(colorLoc, 2);
1744 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1745 glEnableVertexAttribArray(colorLoc);
1746
1747 positionLoc = glGetAttribLocation(program, "vPosition");
1748 }
1749
1750 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001751 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001752
Martin Radev67a8a012017-09-08 13:03:52 +03001753 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001754 ASSERT_GL_NO_ERROR();
1755
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001756 resolveMultisampledFBO();
Martin Radev0abb7a22017-08-28 15:34:45 +03001757 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1758 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1759 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1760 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1761 }
1762
1763 {
1764 const int kNewNumViews = 3;
1765 vsSource = generateVertexShaderSource(kNewNumViews);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001766 updateFBOs(kViewWidth, kViewHeight, kNewNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001767
Jamie Madill35cd7332018-12-02 12:03:33 -05001768 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource.c_str());
Martin Radev0abb7a22017-08-28 15:34:45 +03001769 ASSERT_NE(0u, vs);
Jamie Madill35cd7332018-12-02 12:03:33 -05001770 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
Martin Radev0abb7a22017-08-28 15:34:45 +03001771 ASSERT_NE(0u, fs);
1772
1773 GLint numAttachedShaders = 0;
1774 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1775
1776 GLuint attachedShaders[2] = {0u};
1777 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1778 for (int i = 0; i < 2; ++i)
1779 {
1780 glDetachShader(program, attachedShaders[i]);
1781 }
1782
1783 glAttachShader(program, vs);
1784 glDeleteShader(vs);
1785
1786 glAttachShader(program, fs);
1787 glDeleteShader(fs);
1788
1789 glBindAttribLocation(program, positionLoc, "vPosition");
1790 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1791 glBindAttribLocation(program, colorLoc, "vColor");
1792
1793 glLinkProgram(program);
1794
Martin Radev67a8a012017-09-08 13:03:52 +03001795 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001796 ASSERT_GL_NO_ERROR();
1797
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001798 resolveMultisampledFBO();
Martin Radev0abb7a22017-08-28 15:34:45 +03001799 for (int i = 0; i < kNewNumViews; ++i)
1800 {
1801 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1802 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1803 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1804 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1805 }
1806 }
1807}
1808
Martin Radevced5c862017-08-17 16:05:29 +03001809// Test that useProgram applies the number of views in computing the final value of the attribute
1810// divisor.
1811TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1812{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001813 if (!requestMultiviewExtension(isMultisampled()))
Martin Radevced5c862017-08-17 16:05:29 +03001814 {
1815 return;
1816 }
1817
Geoff Lang25858162017-11-06 11:25:58 -05001818 // Test failing on P400 graphics card (anglebug.com/2228)
1819 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1820
Olli Etuaho44ae8992018-08-20 15:37:09 +03001821 // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
1822 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001823 if (IsWindows() && IsD3D11())
1824 {
1825 ignoreD3D11SDKLayersWarnings();
1826 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001827
Martin Radevced5c862017-08-17 16:05:29 +03001828 GLVertexArray vao;
1829 glBindVertexArray(vao);
1830 GLBuffer vbo;
1831 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1832 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
1833 Vector2I(3, 0)};
1834 std::vector<Vector2> vertexDataInClipSpace =
1835 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
1836 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
1837 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
1838 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1839 glEnableVertexAttribArray(0);
1840 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
1841 glVertexAttribDivisor(0, 1);
1842 ASSERT_GL_NO_ERROR();
1843
1844 // Create a program and fbo with N views and draw N instances of a point horizontally.
1845 for (int numViews = 2; numViews <= 4; ++numViews)
1846 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001847 updateFBOs(4, 1, numViews);
Martin Radevced5c862017-08-17 16:05:29 +03001848 ASSERT_GL_NO_ERROR();
1849
1850 GLuint program = CreateSimplePassthroughProgram(numViews);
1851 ASSERT_NE(program, 0u);
1852 glUseProgram(program);
1853 ASSERT_GL_NO_ERROR();
1854
1855 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
1856
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001857 resolveMultisampledFBO();
Martin Radevced5c862017-08-17 16:05:29 +03001858 for (int view = 0; view < numViews; ++view)
1859 {
1860 for (int j = 0; j < numViews; ++j)
1861 {
Martin Radev67a8a012017-09-08 13:03:52 +03001862 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03001863 }
1864 for (int j = numViews; j < 4; ++j)
1865 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001866 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03001867 }
1868 }
1869
1870 glDeleteProgram(program);
1871 }
1872}
1873
Martin Radev72b4e1e2017-08-31 15:42:56 +03001874// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
1875TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
1876{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001877 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev72b4e1e2017-08-31 15:42:56 +03001878 {
1879 return;
1880 }
1881
Jamie Madill35cd7332018-12-02 12:03:33 -05001882 constexpr char kVS[] =
Martin Radev72b4e1e2017-08-31 15:42:56 +03001883 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001884 "#extension GL_OVR_multiview2 : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001885 "layout(num_views = 3) in;\n"
1886 "in vec3 vPosition;\n"
1887 "void main()\n"
1888 "{\n"
1889 " gl_Position = vec4(vPosition, 1.);\n"
1890 "}\n";
1891
Jamie Madill35cd7332018-12-02 12:03:33 -05001892 constexpr char kFS[] =
Martin Radev72b4e1e2017-08-31 15:42:56 +03001893 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001894 "#extension GL_OVR_multiview2 : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001895 "precision mediump float;\n"
1896 "out vec4 col;\n"
1897 "void main()\n"
1898 "{\n"
1899 " if (gl_ViewID_OVR == 0u) {\n"
1900 " col = vec4(1,0,0,1);\n"
1901 " } else if (gl_ViewID_OVR == 1u) {\n"
1902 " col = vec4(0,1,0,1);\n"
1903 " } else if (gl_ViewID_OVR == 2u) {\n"
1904 " col = vec4(0,0,1,1);\n"
1905 " } else {\n"
1906 " col = vec4(0,0,0,0);\n"
1907 " }\n"
1908 "}\n";
1909
Olli Etuaho4836acc2018-08-20 15:23:18 +03001910 updateFBOs(1, 1, 3);
Jamie Madill35cd7332018-12-02 12:03:33 -05001911 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev72b4e1e2017-08-31 15:42:56 +03001912
1913 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1914 ASSERT_GL_NO_ERROR();
1915
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001916 resolveMultisampledFBO();
Martin Radev72b4e1e2017-08-31 15:42:56 +03001917 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1918 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1919 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
1920}
1921
1922// The test checks that the inactive layers of a 2D texture array are not written to by a
1923// multi-view program.
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001924TEST_P(MultiviewLayeredRenderTest, RenderToSubrangeOfLayers)
Martin Radev72b4e1e2017-08-31 15:42:56 +03001925{
1926 if (!requestMultiviewExtension())
1927 {
1928 return;
1929 }
1930
Jamie Madill35cd7332018-12-02 12:03:33 -05001931 constexpr char kVS[] =
Martin Radev72b4e1e2017-08-31 15:42:56 +03001932 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001933 "#extension GL_OVR_multiview2 : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001934 "layout(num_views = 2) in;\n"
1935 "in vec3 vPosition;\n"
1936 "void main()\n"
1937 "{\n"
1938 " gl_Position = vec4(vPosition, 1.);\n"
1939 "}\n";
1940
Jamie Madill35cd7332018-12-02 12:03:33 -05001941 constexpr char kFS[] =
Martin Radev72b4e1e2017-08-31 15:42:56 +03001942 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001943 "#extension GL_OVR_multiview2 : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001944 "precision mediump float;\n"
1945 "out vec4 col;\n"
1946 "void main()\n"
1947 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001948 " col = vec4(0,1,0,1);\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001949 "}\n";
1950
Olli Etuaho4836acc2018-08-20 15:23:18 +03001951 updateFBOs(1, 1, 2, 4, 1);
Jamie Madill35cd7332018-12-02 12:03:33 -05001952 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radev72b4e1e2017-08-31 15:42:56 +03001953
1954 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1955 ASSERT_GL_NO_ERROR();
1956
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001957 resolveMultisampledFBO();
Martin Radev72b4e1e2017-08-31 15:42:56 +03001958 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +03001959 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1960 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03001961 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
1962}
1963
Martin Radevc1d4e552017-08-21 12:01:10 +03001964// The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
1965// potential bugs if the view is selected in the VS. The test contains a program in which the
1966// gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
1967// fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
1968// never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
1969// green for view 1.
1970TEST_P(MultiviewRenderTest, FlatInterpolation)
Martin Radev3c25ad02017-08-22 17:36:53 +03001971{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001972 if (!requestMultiviewExtension(isMultisampled()))
Martin Radevc1d4e552017-08-21 12:01:10 +03001973 {
1974 return;
1975 }
1976
Jamie Madill35cd7332018-12-02 12:03:33 -05001977 constexpr char kVS[] =
Martin Radevc1d4e552017-08-21 12:01:10 +03001978 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001979 "#extension GL_OVR_multiview2 : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03001980 "layout(num_views = 2) in;\n"
1981 "in vec3 vPosition;\n"
1982 "flat out int oInstanceID;\n"
1983 "void main()\n"
1984 "{\n"
1985 " gl_Position = vec4(vPosition, 1.);\n"
1986 " oInstanceID = gl_InstanceID;\n"
1987 "}\n";
1988
Jamie Madill35cd7332018-12-02 12:03:33 -05001989 constexpr char kFS[] =
Martin Radevc1d4e552017-08-21 12:01:10 +03001990 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07001991 "#extension GL_OVR_multiview2 : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03001992 "precision mediump float;\n"
1993 "flat in int oInstanceID;\n"
1994 "out vec4 col;\n"
1995 "void main()\n"
1996 "{\n"
1997 " if (oInstanceID < 0) {\n"
1998 " discard;\n"
1999 " }\n"
2000 " if (gl_ViewID_OVR == 0u) {\n"
2001 " col = vec4(1,0,0,1);\n"
2002 " } else {\n"
2003 " col = vec4(0,1,0,1);\n"
2004 " }\n"
2005 "}\n";
2006
Olli Etuaho4836acc2018-08-20 15:23:18 +03002007 updateFBOs(1, 1, 2);
Jamie Madill35cd7332018-12-02 12:03:33 -05002008 ANGLE_GL_PROGRAM(program, kVS, kFS);
Martin Radevc1d4e552017-08-21 12:01:10 +03002009
2010 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2011 ASSERT_GL_NO_ERROR();
2012
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002013 resolveMultisampledFBO();
Martin Radevc1d4e552017-08-21 12:01:10 +03002014 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2015 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +03002016}
2017
Olli Etuaho604d8732018-07-20 11:02:43 +03002018// This test assigns gl_ViewID_OVR to a flat int varying and then sets the color based on that
2019// varying in the fragment shader.
2020TEST_P(MultiviewRenderTest, FlatInterpolation2)
2021{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002022 if (!requestMultiviewExtension(isMultisampled()))
Olli Etuaho604d8732018-07-20 11:02:43 +03002023 {
2024 return;
2025 }
2026
Jamie Madill35cd7332018-12-02 12:03:33 -05002027 constexpr char kVS[] =
Olli Etuaho604d8732018-07-20 11:02:43 +03002028 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07002029 "#extension GL_OVR_multiview2 : require\n"
Olli Etuaho604d8732018-07-20 11:02:43 +03002030 "layout(num_views = 2) in;\n"
2031 "in vec3 vPosition;\n"
2032 "flat out int flatVarying;\n"
2033 "void main()\n"
2034 "{\n"
2035 " gl_Position = vec4(vPosition, 1.);\n"
2036 " flatVarying = int(gl_ViewID_OVR);\n"
2037 "}\n";
2038
Jamie Madill35cd7332018-12-02 12:03:33 -05002039 constexpr char kFS[] =
Olli Etuaho604d8732018-07-20 11:02:43 +03002040 "#version 300 es\n"
Mingyu Hu7d64c482019-03-12 14:27:40 -07002041 "#extension GL_OVR_multiview2 : require\n"
Olli Etuaho604d8732018-07-20 11:02:43 +03002042 "precision mediump float;\n"
2043 "flat in int flatVarying;\n"
2044 "out vec4 col;\n"
2045 "void main()\n"
2046 "{\n"
2047 " if (flatVarying == 0) {\n"
2048 " col = vec4(1,0,0,1);\n"
2049 " } else {\n"
2050 " col = vec4(0,1,0,1);\n"
2051 " }\n"
2052 "}\n";
2053
Olli Etuaho4836acc2018-08-20 15:23:18 +03002054 updateFBOs(1, 1, 2);
Jamie Madill35cd7332018-12-02 12:03:33 -05002055 ANGLE_GL_PROGRAM(program, kVS, kFS);
Olli Etuaho604d8732018-07-20 11:02:43 +03002056
2057 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2058 ASSERT_GL_NO_ERROR();
2059
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002060 resolveMultisampledFBO();
Olli Etuaho604d8732018-07-20 11:02:43 +03002061 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2062 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2063}
2064
Mingyu Hu7d64c482019-03-12 14:27:40 -07002065MultiviewRenderTestParams VertexShaderOpenGL()
Martin Radev265a6d42017-09-12 16:51:37 +03002066{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002067 return MultiviewRenderTestParams(0, VertexShaderOpenGL(3, 0));
Martin Radev265a6d42017-09-12 16:51:37 +03002068}
2069
Mingyu Hu7d64c482019-03-12 14:27:40 -07002070MultiviewRenderTestParams GeomShaderD3D11()
Martin Radev3c25ad02017-08-22 17:36:53 +03002071{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002072 return MultiviewRenderTestParams(0, GeomShaderD3D11(3, 0));
Martin Radev3c25ad02017-08-22 17:36:53 +03002073}
2074
Mingyu Hu7d64c482019-03-12 14:27:40 -07002075MultiviewRenderTestParams VertexShaderD3D11()
Martin Radev3c25ad02017-08-22 17:36:53 +03002076{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002077 return MultiviewRenderTestParams(0, VertexShaderD3D11(3, 0));
Martin Radev3c25ad02017-08-22 17:36:53 +03002078}
2079
Mingyu Hu7d64c482019-03-12 14:27:40 -07002080MultiviewRenderTestParams MultisampledVertexShaderOpenGL()
Martin Radev72b4e1e2017-08-31 15:42:56 +03002081{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002082 return MultiviewRenderTestParams(2, VertexShaderOpenGL(3, 1));
Martin Radevc1d4e552017-08-21 12:01:10 +03002083}
2084
Mingyu Hu7d64c482019-03-12 14:27:40 -07002085MultiviewRenderTestParams MultisampledVertexShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002086{
Mingyu Hu7d64c482019-03-12 14:27:40 -07002087 return MultiviewRenderTestParams(2, VertexShaderD3D11(3, 1));
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002088}
2089
Jamie Madill04c084d2018-08-08 15:49:28 -04002090ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest,
Olli Etuaho44ae8992018-08-20 15:37:09 +03002091 VertexShaderOpenGL(3, 1),
2092 VertexShaderD3D11(3, 1));
Martin Radevced5c862017-08-17 16:05:29 +03002093ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
Mingyu Hu7d64c482019-03-12 14:27:40 -07002094 VertexShaderOpenGL(),
2095 MultisampledVertexShaderOpenGL(),
2096 GeomShaderD3D11(),
2097 VertexShaderD3D11(),
2098 MultisampledVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002099ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
Mingyu Hu7d64c482019-03-12 14:27:40 -07002100 VertexShaderOpenGL(),
2101 MultisampledVertexShaderOpenGL(),
2102 GeomShaderD3D11(),
2103 VertexShaderD3D11(),
2104 MultisampledVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002105ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
Mingyu Hu7d64c482019-03-12 14:27:40 -07002106 VertexShaderOpenGL(),
2107 GeomShaderD3D11(),
2108 VertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002109ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
Olli Etuaho4bcaf992018-08-17 17:18:28 +03002110 VertexShaderOpenGL(3, 0),
2111 GeomShaderD3D11(3, 0),
2112 VertexShaderD3D11(3, 0));
Martin Radevced5c862017-08-17 16:05:29 +03002113ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
Mingyu Hu7d64c482019-03-12 14:27:40 -07002114 VertexShaderOpenGL(),
2115 GeomShaderD3D11(),
2116 VertexShaderD3D11());
Jamie Madill04c084d2018-08-08 15:49:28 -04002117ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, VertexShaderOpenGL(3, 0), GeomShaderD3D11(3, 0));