blob: ef54bc813de6441514729f74564d2e3b5f79ae05 [file] [log] [blame]
Martin Radev14a26ae2017-07-24 15:56:29 +03001//
2// Copyright 2017 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6// Multiview draw tests:
7// Test issuing multiview Draw* commands.
8//
9
Martin Radevc1d4e552017-08-21 12:01:10 +030010#include "platform/WorkaroundsD3D.h"
Olli Etuahof26b27e2018-08-17 11:01:19 +030011#include "test_utils/MultiviewTest.h"
Martin Radev14a26ae2017-07-24 15:56:29 +030012#include "test_utils/gl_raii.h"
13
14using namespace angle;
15
Martin Radev61bd9992017-08-11 13:10:55 +030016namespace
17{
Martin Radev61bd9992017-08-11 13:10:55 +030018
19std::vector<Vector2> ConvertPixelCoordinatesToClipSpace(const std::vector<Vector2I> &pixels,
20 int width,
21 int height)
22{
23 std::vector<Vector2> result(pixels.size());
24 for (size_t i = 0; i < pixels.size(); ++i)
25 {
26 const auto &pixel = pixels[i];
27 float pixelCenterRelativeX = (static_cast<float>(pixel.x()) + .5f) / width;
28 float pixelCenterRelativeY = (static_cast<float>(pixel.y()) + .5f) / height;
29 float xInClipSpace = 2.f * pixelCenterRelativeX - 1.f;
30 float yInClipSpace = 2.f * pixelCenterRelativeY - 1.f;
31 result[i] = Vector2(xInClipSpace, yInClipSpace);
32 }
33 return result;
34}
35} // namespace
36
Olli Etuahof26b27e2018-08-17 11:01:19 +030037struct MultiviewRenderTestParams final : public MultiviewImplementationParams
Martin Radev3c25ad02017-08-22 17:36:53 +030038{
Olli Etuahof26b27e2018-08-17 11:01:19 +030039 MultiviewRenderTestParams(GLenum multiviewLayout,
Olli Etuaho2c8f0842018-09-12 14:44:55 +030040 int samples,
Olli Etuahof26b27e2018-08-17 11:01:19 +030041 const MultiviewImplementationParams &implementationParams)
Olli Etuaho2c8f0842018-09-12 14:44:55 +030042 : MultiviewImplementationParams(implementationParams),
43 mMultiviewLayout(multiviewLayout),
44 mSamples(samples)
Martin Radev3c25ad02017-08-22 17:36:53 +030045 {
46 ASSERT(multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE ||
47 multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
48 }
49 GLenum mMultiviewLayout;
Olli Etuaho2c8f0842018-09-12 14:44:55 +030050 int mSamples;
Martin Radev3c25ad02017-08-22 17:36:53 +030051};
52
Olli Etuahof26b27e2018-08-17 11:01:19 +030053std::ostream &operator<<(std::ostream &os, const MultiviewRenderTestParams &params)
Martin Radev3c25ad02017-08-22 17:36:53 +030054{
Martin Radevc1d4e552017-08-21 12:01:10 +030055 const MultiviewImplementationParams &base =
56 static_cast<const MultiviewImplementationParams &>(params);
Martin Radev3c25ad02017-08-22 17:36:53 +030057 os << base;
58 switch (params.mMultiviewLayout)
59 {
60 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
61 os << "_layered";
62 break;
63 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
64 os << "_side_by_side";
65 break;
66 default:
67 UNREACHABLE();
68 }
Olli Etuaho2c8f0842018-09-12 14:44:55 +030069 if (params.mSamples > 0)
70 {
71 os << "_samples_" << params.mSamples;
72 }
Martin Radev3c25ad02017-08-22 17:36:53 +030073 return os;
74}
75
Olli Etuaho4836acc2018-08-20 15:23:18 +030076class MultiviewFramebufferTestBase : public MultiviewTestBase
Martin Radev8f276e22017-05-30 12:05:52 +030077{
78 protected:
Olli Etuaho2c8f0842018-09-12 14:44:55 +030079 MultiviewFramebufferTestBase(const PlatformParameters &params,
80 GLenum multiviewLayout,
81 int samples)
Olli Etuahof26b27e2018-08-17 11:01:19 +030082 : MultiviewTestBase(params),
Martin Radev3c25ad02017-08-22 17:36:53 +030083 mViewWidth(0),
84 mViewHeight(0),
Olli Etuaho4836acc2018-08-20 15:23:18 +030085 mNumViews(0),
Olli Etuaho44ae8992018-08-20 15:37:09 +030086 mColorTexture(0u),
87 mDepthTexture(0u),
88 mDrawFramebuffer(0u),
Olli Etuaho2c8f0842018-09-12 14:44:55 +030089 mMultiviewLayout(multiviewLayout),
90 mSamples(samples),
91 mResolveTexture(0u)
Jamie Madillb980c562018-11-27 11:34:27 -050092 {}
Olli Etuaho44ae8992018-08-20 15:37:09 +030093
Olli Etuaho4836acc2018-08-20 15:23:18 +030094 void FramebufferTestSetUp() { MultiviewTestBase::MultiviewTestBaseSetUp(); }
Olli Etuaho44ae8992018-08-20 15:37:09 +030095
96 void FramebufferTestTearDown()
97 {
98 freeFBOs();
99 MultiviewTestBase::MultiviewTestBaseTearDown();
100 }
101
Olli Etuaho4836acc2018-08-20 15:23:18 +0300102 void updateFBOs(int viewWidth, int height, int numViews, int numLayers, int baseViewIndex)
Martin Radev3c25ad02017-08-22 17:36:53 +0300103 {
Martin Radev72b4e1e2017-08-31 15:42:56 +0300104 ASSERT(numViews + baseViewIndex <= numLayers);
105
Olli Etuaho44ae8992018-08-20 15:37:09 +0300106 freeFBOs();
107
Martin Radev3c25ad02017-08-22 17:36:53 +0300108 mViewWidth = viewWidth;
109 mViewHeight = height;
110 mNumViews = numViews;
Martin Radev8f276e22017-05-30 12:05:52 +0300111
Olli Etuaho44ae8992018-08-20 15:37:09 +0300112 glGenTextures(1, &mColorTexture);
113 glGenTextures(1, &mDepthTexture);
Martin Radev0abb7a22017-08-28 15:34:45 +0300114
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300115 CreateMultiviewBackingTextures(mMultiviewLayout, mSamples, viewWidth, height, numLayers,
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300116 mColorTexture, mDepthTexture, 0u);
Martin Radev3c25ad02017-08-22 17:36:53 +0300117
Olli Etuaho44ae8992018-08-20 15:37:09 +0300118 glGenFramebuffers(1, &mDrawFramebuffer);
119
Martin Radev3c25ad02017-08-22 17:36:53 +0300120 // Create draw framebuffer to be used for multiview rendering.
121 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300122 AttachMultiviewTextures(GL_DRAW_FRAMEBUFFER, mMultiviewLayout, viewWidth, numViews,
123 baseViewIndex, mColorTexture, mDepthTexture, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300124
Martin Radev8f276e22017-05-30 12:05:52 +0300125 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
126
127 // Create read framebuffer to be used to retrieve the pixel information for testing
128 // purposes.
Martin Radev3c25ad02017-08-22 17:36:53 +0300129 switch (mMultiviewLayout)
130 {
131 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
132 mReadFramebuffer.resize(1);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300133 glGenFramebuffers(1, mReadFramebuffer.data());
Martin Radev3c25ad02017-08-22 17:36:53 +0300134 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
135 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
136 mColorTexture, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300137 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
138 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300139 break;
140 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
Martin Radev72b4e1e2017-08-31 15:42:56 +0300141 mReadFramebuffer.resize(numLayers);
Shahbaz Youssefic4097442018-08-22 12:14:52 -0400142 glGenFramebuffers(static_cast<GLsizei>(mReadFramebuffer.size()),
143 mReadFramebuffer.data());
Martin Radev72b4e1e2017-08-31 15:42:56 +0300144 for (int i = 0; i < numLayers; ++i)
Martin Radev3c25ad02017-08-22 17:36:53 +0300145 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300146 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
147 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
148 mColorTexture, 0, i);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300149 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
150 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300151 }
152 break;
153 default:
154 UNREACHABLE();
155 }
Martin Radev8f276e22017-05-30 12:05:52 +0300156
157 // Clear the buffers.
Martin Radev3c25ad02017-08-22 17:36:53 +0300158 glViewport(0, 0, viewWidth, height);
159 if (mMultiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
160 {
161 // Enable the scissor test only for side-by-side framebuffers.
162 glEnable(GL_SCISSOR_TEST);
163 glScissor(0, 0, viewWidth, height);
164 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300165 }
Martin Radev8f276e22017-05-30 12:05:52 +0300166
Olli Etuaho4836acc2018-08-20 15:23:18 +0300167 void updateFBOs(int viewWidth, int height, int numViews)
Martin Radev72b4e1e2017-08-31 15:42:56 +0300168 {
Olli Etuaho4836acc2018-08-20 15:23:18 +0300169 updateFBOs(viewWidth, height, numViews, numViews, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300170 }
171
Olli Etuaho4836acc2018-08-20 15:23:18 +0300172 void bindMemberDrawFramebuffer() { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer); }
173
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300174 // In case we have a multisampled framebuffer, creates and binds a resolve framebuffer as the
175 // draw framebuffer, and resolves the read framebuffer to it.
176 void resolveMultisampledFBO()
177 {
178 if (mSamples == 0)
179 {
180 return;
181 }
182 int numLayers = mReadFramebuffer.size();
183 if (mResolveFramebuffer.empty())
184 {
185 ASSERT(mResolveTexture == 0u);
186 glGenTextures(1, &mResolveTexture);
187 CreateMultiviewBackingTextures(mMultiviewLayout, 0, mViewWidth, mViewHeight, numLayers,
188 mResolveTexture, 0u, 0u);
189
190 mResolveFramebuffer.resize(numLayers);
191 glGenFramebuffers(static_cast<GLsizei>(mResolveFramebuffer.size()),
192 mResolveFramebuffer.data());
193 for (int i = 0; i < numLayers; ++i)
194 {
195 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFramebuffer[i]);
196 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
197 mResolveTexture, 0, i);
198 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
199 glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
200 }
201 }
202 for (int i = 0; i < numLayers; ++i)
203 {
204 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
205 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFramebuffer[i]);
206 glBlitFramebuffer(0, 0, mViewWidth, mViewHeight, 0, 0, mViewWidth, mViewHeight,
207 GL_COLOR_BUFFER_BIT, GL_NEAREST);
208 }
209 }
210
Martin Radev3c25ad02017-08-22 17:36:53 +0300211 GLColor GetViewColor(int x, int y, int view)
212 {
213 switch (mMultiviewLayout)
214 {
215 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300216 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
Martin Radev3c25ad02017-08-22 17:36:53 +0300217 return ReadColor(view * mViewWidth + x, y);
218 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
219 ASSERT(static_cast<size_t>(view) < mReadFramebuffer.size());
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300220 if (mSamples > 0)
221 {
222 ASSERT(static_cast<size_t>(view) < mResolveFramebuffer.size());
223 glBindFramebuffer(GL_READ_FRAMEBUFFER, mResolveFramebuffer[view]);
224 }
225 else
226 {
227 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
228 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300229 return ReadColor(x, y);
230 default:
231 UNREACHABLE();
232 }
233 return GLColor(0, 0, 0, 0);
Martin Radev8f276e22017-05-30 12:05:52 +0300234 }
235
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300236 bool isMultisampled() { return mSamples > 0; }
237
Martin Radev3c25ad02017-08-22 17:36:53 +0300238 int mViewWidth;
239 int mViewHeight;
240 int mNumViews;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300241
Olli Etuaho44ae8992018-08-20 15:37:09 +0300242 GLuint mColorTexture;
243 GLuint mDepthTexture;
244
Olli Etuaho4836acc2018-08-20 15:23:18 +0300245 private:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300246 GLuint mDrawFramebuffer;
247 std::vector<GLuint> mReadFramebuffer;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300248 GLenum mMultiviewLayout;
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300249 int mSamples;
250
251 // For reading back multisampled framebuffer.
252 std::vector<GLuint> mResolveFramebuffer;
253 GLuint mResolveTexture;
Olli Etuaho44ae8992018-08-20 15:37:09 +0300254
255 void freeFBOs()
256 {
257 if (mDrawFramebuffer)
258 {
259 glDeleteFramebuffers(1, &mDrawFramebuffer);
260 mDrawFramebuffer = 0;
261 }
262 if (!mReadFramebuffer.empty())
263 {
Shahbaz Youssefic4097442018-08-22 12:14:52 -0400264 GLsizei framebufferCount = static_cast<GLsizei>(mReadFramebuffer.size());
265 glDeleteFramebuffers(framebufferCount, mReadFramebuffer.data());
Olli Etuaho44ae8992018-08-20 15:37:09 +0300266 mReadFramebuffer.clear();
267 }
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300268 if (!mResolveFramebuffer.empty())
269 {
270 GLsizei framebufferCount = static_cast<GLsizei>(mResolveFramebuffer.size());
271 glDeleteFramebuffers(framebufferCount, mResolveFramebuffer.data());
272 mResolveFramebuffer.clear();
273 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300274 if (mDepthTexture)
275 {
276 glDeleteTextures(1, &mDepthTexture);
277 mDepthTexture = 0;
278 }
279 if (mColorTexture)
280 {
281 glDeleteTextures(1, &mColorTexture);
282 mColorTexture = 0;
283 }
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300284 if (mResolveTexture)
285 {
286 glDeleteTextures(1, &mResolveTexture);
287 mResolveTexture = 0;
288 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300289 }
Martin Radev8f276e22017-05-30 12:05:52 +0300290};
291
Olli Etuaho4836acc2018-08-20 15:23:18 +0300292class MultiviewRenderTest : public MultiviewFramebufferTestBase,
Olli Etuahof26b27e2018-08-17 11:01:19 +0300293 public ::testing::TestWithParam<MultiviewRenderTestParams>
Martin Radev8f276e22017-05-30 12:05:52 +0300294{
295 protected:
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300296 MultiviewRenderTest()
297 : MultiviewFramebufferTestBase(GetParam(), GetParam().mMultiviewLayout, GetParam().mSamples)
Jamie Madillb980c562018-11-27 11:34:27 -0500298 {}
Olli Etuaho4836acc2018-08-20 15:23:18 +0300299 void SetUp() override { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300300 void TearDown() override { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
Martin Radevc1d4e552017-08-21 12:01:10 +0300301
302 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
303 {
304 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
305 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300306};
307
Jamie Madill04c084d2018-08-08 15:49:28 -0400308constexpr char kDualViewVSSource[] = R"(#version 300 es
309#extension GL_OVR_multiview : require
310layout(num_views = 2) in;
311in vec4 vPosition;
312void main()
313{
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300314 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 -0400315 gl_Position.yzw = vPosition.yzw;
316})";
317
318constexpr char kDualViewFSSource[] = R"(#version 300 es
319#extension GL_OVR_multiview : require
320precision mediump float;
321out vec4 col;
322void main()
323{
324 col = vec4(0,1,0,1);
325})";
326
Martin Radev3c25ad02017-08-22 17:36:53 +0300327class MultiviewRenderDualViewTest : public MultiviewRenderTest
328{
329 protected:
330 MultiviewRenderDualViewTest() : mProgram(0u) {}
Martin Radev8f276e22017-05-30 12:05:52 +0300331
332 void SetUp() override
333 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300334 MultiviewRenderTest::SetUp();
Martin Radev8f276e22017-05-30 12:05:52 +0300335
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300336 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +0300337 {
338 return;
339 }
340
Olli Etuaho4836acc2018-08-20 15:23:18 +0300341 updateFBOs(2, 1, 2);
Jamie Madill04c084d2018-08-08 15:49:28 -0400342 mProgram = CompileProgram(kDualViewVSSource, kDualViewFSSource);
Martin Radev61bd9992017-08-11 13:10:55 +0300343 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300344 glUseProgram(mProgram);
345 ASSERT_GL_NO_ERROR();
346 }
347
Olli Etuaho44ae8992018-08-20 15:37:09 +0300348 void TearDown() override
349 {
350 if (mProgram != 0u)
351 {
352 glDeleteProgram(mProgram);
353 mProgram = 0u;
354 }
355
356 MultiviewRenderTest::TearDown();
357 }
358
Martin Radev8f276e22017-05-30 12:05:52 +0300359 void checkOutput()
360 {
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300361 resolveMultisampledFBO();
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300362 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +0300363 EXPECT_EQ(GLColor::green, GetViewColor(1, 0, 0));
364 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300365 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(1, 0, 1));
Martin Radev8f276e22017-05-30 12:05:52 +0300366 }
367
368 GLuint mProgram;
369};
370
Olli Etuaho44ae8992018-08-20 15:37:09 +0300371// Base class for tests that care mostly about draw call validity and not rendering results.
372class MultiviewDrawValidationTest : public MultiviewTest
Jamie Madill04c084d2018-08-08 15:49:28 -0400373{
374 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300375 MultiviewDrawValidationTest() : MultiviewTest() {}
Jamie Madill04c084d2018-08-08 15:49:28 -0400376
Olli Etuaho44ae8992018-08-20 15:37:09 +0300377 void initOnePixelColorTexture2D(GLuint texId)
Jamie Madill04c084d2018-08-08 15:49:28 -0400378 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300379 glBindTexture(GL_TEXTURE_2D, texId);
Jamie Madill04c084d2018-08-08 15:49:28 -0400380 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300381 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400382
Olli Etuaho44ae8992018-08-20 15:37:09 +0300383 // This initializes a simple VAO with a valid vertex buffer and index buffer with three
384 // vertices.
385 void initVAO(GLuint vao, GLuint vertexBuffer, GLuint indexBuffer)
386 {
387 glBindVertexArray(vao);
Jamie Madill04c084d2018-08-08 15:49:28 -0400388
389 const float kVertexData[3] = {0.0f};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300390 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400391 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
392
393 const unsigned int kIndices[3] = {0u, 1u, 2u};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300394 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400395 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
396 GL_STATIC_DRAW);
397 ASSERT_GL_NO_ERROR();
398 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400399};
400
Martin Radev3c25ad02017-08-22 17:36:53 +0300401class MultiviewOcclusionQueryTest : public MultiviewRenderTest
Martin Radev0d671c92017-08-10 16:41:52 +0300402{
403 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300404 MultiviewOcclusionQueryTest() {}
Martin Radev0d671c92017-08-10 16:41:52 +0300405
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400406 bool requestOcclusionQueryExtension()
407 {
408 if (extensionRequestable("GL_EXT_occlusion_query_boolean"))
409 {
410 glRequestExtensionANGLE("GL_EXT_occlusion_query_boolean");
411 }
412
413 if (!extensionEnabled("GL_EXT_occlusion_query_boolean"))
414 {
415 std::cout << "Test skipped due to missing GL_EXT_occlusion_query_boolean." << std::endl;
416 return false;
417 }
418 return true;
419 }
420
Martin Radev0d671c92017-08-10 16:41:52 +0300421 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
422 {
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400423 GLQueryEXT query;
424 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED, query);
Martin Radev0d671c92017-08-10 16:41:52 +0300425 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
426 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
427
428 GLuint result = GL_TRUE;
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400429 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT, &result);
Martin Radev0d671c92017-08-10 16:41:52 +0300430 return result;
431 }
432};
433
Olli Etuaho4bcaf992018-08-17 17:18:28 +0300434class MultiviewProgramGenerationTest : public MultiviewTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300435{
436 protected:
437 MultiviewProgramGenerationTest() {}
438};
439
Martin Radev3c25ad02017-08-22 17:36:53 +0300440class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300441{
442 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300443 MultiviewRenderPrimitiveTest() : mVBO(0u) {}
444
445 void SetUp() override
446 {
447 MultiviewRenderTest::SetUp();
448 glGenBuffers(1, &mVBO);
449 }
450
451 void TearDown() override
452 {
453 if (mVBO)
454 {
455 glDeleteBuffers(1, &mVBO);
456 mVBO = 0u;
457 }
458 MultiviewRenderTest::TearDown();
459 }
Martin Radev61bd9992017-08-11 13:10:55 +0300460
461 void setupGeometry(const std::vector<Vector2> &vertexData)
462 {
Martin Radev61bd9992017-08-11 13:10:55 +0300463 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
464 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
465 GL_STATIC_DRAW);
466 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500467 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +0300468 }
469
Martin Radev67a8a012017-09-08 13:03:52 +0300470 void checkGreenChannel(const GLubyte expectedGreenChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300471 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300472 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300473 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300474 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300475 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300476 for (int h = 0; h < mViewHeight; ++h)
477 {
478 size_t flatIndex =
479 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300480 EXPECT_EQ(GLColor(0, expectedGreenChannelData[flatIndex], 0,
481 expectedGreenChannelData[flatIndex]),
Martin Radev3c25ad02017-08-22 17:36:53 +0300482 GetViewColor(w, h, view));
483 }
Martin Radev61bd9992017-08-11 13:10:55 +0300484 }
485 }
486 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300487 GLuint mVBO;
Martin Radev61bd9992017-08-11 13:10:55 +0300488};
489
Olli Etuaho4836acc2018-08-20 15:23:18 +0300490class MultiviewSideBySideRenderTest : public MultiviewFramebufferTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300491 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev3c25ad02017-08-22 17:36:53 +0300492{
493 protected:
494 MultiviewSideBySideRenderTest()
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300495 : MultiviewFramebufferTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, 0)
Jamie Madillb980c562018-11-27 11:34:27 -0500496 {}
Olli Etuaho44ae8992018-08-20 15:37:09 +0300497
498 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
499 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
500 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
Martin Radevc1d4e552017-08-21 12:01:10 +0300501 {
502 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
503 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300504};
505
Olli Etuaho4836acc2018-08-20 15:23:18 +0300506class MultiviewLayeredRenderTest : public MultiviewFramebufferTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300507 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev72b4e1e2017-08-31 15:42:56 +0300508{
509 protected:
510 MultiviewLayeredRenderTest()
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300511 : MultiviewFramebufferTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, 0)
Jamie Madillb980c562018-11-27 11:34:27 -0500512 {}
Olli Etuaho44ae8992018-08-20 15:37:09 +0300513 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
514 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
515 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
Martin Radevc1d4e552017-08-21 12:01:10 +0300516 {
517 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
518 }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300519};
520
Martin Radev14a26ae2017-07-24 15:56:29 +0300521// The test verifies that glDraw*Indirect:
522// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
523// than 1.
524// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +0300525TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300526{
527 if (!requestMultiviewExtension())
528 {
529 return;
530 }
531
Martin Radev14a26ae2017-07-24 15:56:29 +0300532 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +0300533
534 const std::string fsSource =
535 "#version 300 es\n"
536 "#extension GL_OVR_multiview : require\n"
537 "precision mediump float;\n"
538 "void main()\n"
539 "{}\n";
540
Olli Etuaho44ae8992018-08-20 15:37:09 +0300541 GLVertexArray vao;
542 GLBuffer vertexBuffer;
543 GLBuffer indexBuffer;
544 initVAO(vao, vertexBuffer, indexBuffer);
545
546 GLFramebuffer fbo;
547 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
548
Martin Radev14a26ae2017-07-24 15:56:29 +0300549 GLBuffer commandBuffer;
550 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
551 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
552 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
553 ASSERT_GL_NO_ERROR();
554
Olli Etuaho44ae8992018-08-20 15:37:09 +0300555 GLTexture tex2D;
556 initOnePixelColorTexture2D(tex2D);
557
Martin Radev14a26ae2017-07-24 15:56:29 +0300558 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
559 {
560 const std::string &vsSource =
561 "#version 300 es\n"
562 "#extension GL_OVR_multiview : require\n"
563 "layout(num_views = 2) in;\n"
564 "void main()\n"
565 "{}\n";
566 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
567 glUseProgram(program);
568
Olli Etuaho44ae8992018-08-20 15:37:09 +0300569 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
570 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300571
572 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
573 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
574
575 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
576 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
577 }
578
579 // Check that no errors are generated if the number of views is 1.
580 {
581 const std::string &vsSource =
582 "#version 300 es\n"
583 "#extension GL_OVR_multiview : require\n"
584 "layout(num_views = 1) in;\n"
585 "void main()\n"
586 "{}\n";
587 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
588 glUseProgram(program);
589
Olli Etuaho44ae8992018-08-20 15:37:09 +0300590 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
591 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300592
593 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
594 EXPECT_GL_NO_ERROR();
595
596 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
597 EXPECT_GL_NO_ERROR();
598 }
599}
600
Martin Radev7cf61662017-07-26 17:10:53 +0300601// The test verifies that glDraw*:
602// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
603// program differs.
604// 2) does not generate any error if the number of views is the same.
Martin Radev7cf61662017-07-26 17:10:53 +0300605TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
606{
607 if (!requestMultiviewExtension())
608 {
609 return;
610 }
611
612 const GLint viewportOffsets[4] = {0, 0, 2, 0};
613
614 const std::string &vsSource =
615 "#version 300 es\n"
616 "#extension GL_OVR_multiview : require\n"
617 "layout(num_views = 2) in;\n"
618 "void main()\n"
619 "{}\n";
620 const std::string &fsSource =
621 "#version 300 es\n"
622 "#extension GL_OVR_multiview : require\n"
623 "precision mediump float;\n"
624 "void main()\n"
625 "{}\n";
626 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
627 glUseProgram(program);
628
Olli Etuaho44ae8992018-08-20 15:37:09 +0300629 GLVertexArray vao;
630 GLBuffer vertexBuffer;
631 GLBuffer indexBuffer;
632 initVAO(vao, vertexBuffer, indexBuffer);
633
634 GLFramebuffer fbo;
635 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
636
637 GLTexture tex2D;
638 initOnePixelColorTexture2D(tex2D);
639
Martin Radev7cf61662017-07-26 17:10:53 +0300640 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
641 // number of views.
642 {
643 // The framebuffer has only 1 view.
Olli Etuaho44ae8992018-08-20 15:37:09 +0300644 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
645 1, &viewportOffsets[0]);
Martin Radev7cf61662017-07-26 17:10:53 +0300646
647 glDrawArrays(GL_TRIANGLES, 0, 3);
648 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
649
650 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
651 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
652 }
653
654 // Check that no errors are generated if the number of views in both program and draw
655 // framebuffer matches.
656 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300657 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
658 2, &viewportOffsets[0]);
Martin Radev7cf61662017-07-26 17:10:53 +0300659
660 glDrawArrays(GL_TRIANGLES, 0, 3);
661 EXPECT_GL_NO_ERROR();
662
663 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
664 EXPECT_GL_NO_ERROR();
665 }
Martin Radevda8e2572017-09-12 17:21:16 +0300666}
Martin Radev7cf61662017-07-26 17:10:53 +0300667
Martin Radevda8e2572017-09-12 17:21:16 +0300668// The test verifies that glDraw* generates an INVALID_OPERATION error if the program does not use
669// the multiview extension, but the active draw framebuffer has more than one view.
670TEST_P(MultiviewDrawValidationTest, NumViewsMismatchForNonMultiviewProgram)
671{
672 if (!requestMultiviewExtension())
Martin Radev7cf61662017-07-26 17:10:53 +0300673 {
Martin Radevda8e2572017-09-12 17:21:16 +0300674 return;
Martin Radev7cf61662017-07-26 17:10:53 +0300675 }
Martin Radevda8e2572017-09-12 17:21:16 +0300676
677 const std::string &vsSourceNoMultiview =
678 "#version 300 es\n"
679 "void main()\n"
680 "{}\n";
681 const std::string &fsSourceNoMultiview =
682 "#version 300 es\n"
683 "precision mediump float;\n"
684 "void main()\n"
685 "{}\n";
686 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
687 glUseProgram(programNoMultiview);
688
Olli Etuaho44ae8992018-08-20 15:37:09 +0300689 GLVertexArray vao;
690 GLBuffer vertexBuffer;
691 GLBuffer indexBuffer;
692 initVAO(vao, vertexBuffer, indexBuffer);
693
694 GLFramebuffer fbo;
695 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
696
697 GLTexture tex2D;
698 initOnePixelColorTexture2D(tex2D);
699
Martin Radevda8e2572017-09-12 17:21:16 +0300700 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300701 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 2,
Martin Radevda8e2572017-09-12 17:21:16 +0300702 &viewportOffsets[0]);
703
704 glDrawArrays(GL_TRIANGLES, 0, 3);
705 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
706
707 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
708 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radev7cf61662017-07-26 17:10:53 +0300709}
710
Martin Radev7e69f762017-07-27 14:54:13 +0300711// The test verifies that glDraw*:
712// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
713// greater than 1 and there is an active transform feedback object.
714// 2) does not generate any error if the number of views in the draw framebuffer is 1.
715TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
716{
717 if (!requestMultiviewExtension())
718 {
719 return;
720 }
721
722 const GLint viewportOffsets[4] = {0, 0, 2, 0};
723
724 const std::string &vsSource =
Olli Etuaho3755c482017-10-13 15:40:26 +0300725 R"(#version 300 es
726 out float tfVarying;
727 void main()
728 {
729 tfVarying = 1.0;
730 })";
Martin Radev7e69f762017-07-27 14:54:13 +0300731 const std::string &fsSource =
Olli Etuaho3755c482017-10-13 15:40:26 +0300732 R"(#version 300 es
733 precision mediump float;
734 void main()
735 {})";
Jamie Madill04c084d2018-08-08 15:49:28 -0400736
Olli Etuaho3755c482017-10-13 15:40:26 +0300737 std::vector<std::string> tfVaryings;
Jamie Madill04c084d2018-08-08 15:49:28 -0400738 tfVaryings.emplace_back("tfVarying");
739 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(singleViewProgram, vsSource, fsSource, tfVaryings,
Olli Etuaho3755c482017-10-13 15:40:26 +0300740 GL_SEPARATE_ATTRIBS);
Jamie Madill04c084d2018-08-08 15:49:28 -0400741
742 std::vector<std::string> dualViewTFVaryings;
743 dualViewTFVaryings.emplace_back("gl_Position");
744 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(dualViewProgram, kDualViewVSSource, kDualViewFSSource,
745 dualViewTFVaryings, GL_SEPARATE_ATTRIBS);
Martin Radev7e69f762017-07-27 14:54:13 +0300746
Olli Etuaho44ae8992018-08-20 15:37:09 +0300747 GLVertexArray vao;
748 GLBuffer vertexBuffer;
749 GLBuffer indexBuffer;
750 initVAO(vao, vertexBuffer, indexBuffer);
751
Martin Radev7e69f762017-07-27 14:54:13 +0300752 GLBuffer tbo;
753 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
Jamie Madill04c084d2018-08-08 15:49:28 -0400754 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 16u, nullptr, GL_STATIC_DRAW);
Martin Radev7e69f762017-07-27 14:54:13 +0300755
756 GLTransformFeedback transformFeedback;
757 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
Olli Etuaho3755c482017-10-13 15:40:26 +0300758
759 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
760
Jamie Madill04c084d2018-08-08 15:49:28 -0400761 glUseProgram(dualViewProgram);
Martin Radev7e69f762017-07-27 14:54:13 +0300762 glBeginTransformFeedback(GL_TRIANGLES);
763 ASSERT_GL_NO_ERROR();
764
Olli Etuaho44ae8992018-08-20 15:37:09 +0300765 GLFramebuffer fbo;
766 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
767
768 GLTexture tex2D;
769 initOnePixelColorTexture2D(tex2D);
770
Martin Radev7e69f762017-07-27 14:54:13 +0300771 // Check that drawArrays generates an error when there is an active transform feedback object
772 // and the number of views in the draw framebuffer is greater than 1.
773 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300774 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
775 2, &viewportOffsets[0]);
Martin Radev7e69f762017-07-27 14:54:13 +0300776 glDrawArrays(GL_TRIANGLES, 0, 3);
777 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
778 }
779
Jamie Madill04c084d2018-08-08 15:49:28 -0400780 glEndTransformFeedback();
781
782 // Ending transform feedback should allow the draw to succeed.
783 {
784 glDrawArrays(GL_TRIANGLES, 0, 3);
785 EXPECT_GL_NO_ERROR();
786 }
787
788 // A paused transform feedback should still trigger an error.
789 glBeginTransformFeedback(GL_TRIANGLES);
790 glPauseTransformFeedback();
791 ASSERT_GL_NO_ERROR();
792
793 glDrawArrays(GL_TRIANGLES, 0, 3);
794 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
795
796 // Unbind transform feedback - should succeed.
797 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
798 glDrawArrays(GL_TRIANGLES, 0, 3);
799 ASSERT_GL_NO_ERROR();
800
801 // Rebind paused transform feedback - should fail.
802 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
803 glDrawArrays(GL_TRIANGLES, 0, 3);
804 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
805
806 glResumeTransformFeedback();
807 glEndTransformFeedback();
808
809 glUseProgram(singleViewProgram);
810 glBeginTransformFeedback(GL_TRIANGLES);
811 ASSERT_GL_NO_ERROR();
812
Martin Radev7e69f762017-07-27 14:54:13 +0300813 // Check that drawArrays does not generate an error when the number of views in the draw
814 // framebuffer is 1.
815 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300816 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
817 1, &viewportOffsets[0]);
Martin Radev7e69f762017-07-27 14:54:13 +0300818 glDrawArrays(GL_TRIANGLES, 0, 3);
819 EXPECT_GL_NO_ERROR();
820 }
821
822 glEndTransformFeedback();
823}
824
Martin Radevffe754b2017-07-31 10:38:07 +0300825// The test verifies that glDraw*:
826// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
827// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
828// 2) does not generate any error if the number of views in the draw framebuffer is 1.
829TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
830{
Yunchao He9550c602018-02-13 14:47:05 +0800831 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radevffe754b2017-07-31 10:38:07 +0300832
Olli Etuaho94c91a92018-07-19 15:10:24 +0300833 if (extensionRequestable("GL_EXT_disjoint_timer_query"))
834 {
835 glRequestExtensionANGLE("GL_EXT_disjoint_timer_query");
836 }
837
Yunchao He9550c602018-02-13 14:47:05 +0800838 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_disjoint_timer_query"));
Martin Radevffe754b2017-07-31 10:38:07 +0300839
Olli Etuaho44ae8992018-08-20 15:37:09 +0300840 ANGLE_GL_PROGRAM(dualViewProgram, kDualViewVSSource, kDualViewFSSource);
841
Martin Radevffe754b2017-07-31 10:38:07 +0300842 const GLint viewportOffsets[4] = {0, 0, 2, 0};
843 const std::string &vsSource =
844 "#version 300 es\n"
845 "void main()\n"
846 "{}\n";
847 const std::string &fsSource =
848 "#version 300 es\n"
849 "precision mediump float;\n"
850 "void main()\n"
851 "{}\n";
Jamie Madill04c084d2018-08-08 15:49:28 -0400852 ANGLE_GL_PROGRAM(singleViewProgram, vsSource, fsSource);
853 glUseProgram(singleViewProgram);
Martin Radevffe754b2017-07-31 10:38:07 +0300854
Olli Etuaho44ae8992018-08-20 15:37:09 +0300855 GLVertexArray vao;
856 GLBuffer vertexBuffer;
857 GLBuffer indexBuffer;
858 initVAO(vao, vertexBuffer, indexBuffer);
859
Martin Radevffe754b2017-07-31 10:38:07 +0300860 GLuint query = 0u;
861 glGenQueriesEXT(1, &query);
862 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
863
Olli Etuaho44ae8992018-08-20 15:37:09 +0300864 GLFramebuffer fbo;
865 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
866
867 GLTexture tex2D;
868 initOnePixelColorTexture2D(tex2D);
869
Martin Radevffe754b2017-07-31 10:38:07 +0300870 // Check first case.
871 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300872 glUseProgram(dualViewProgram);
873 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
874 2, &viewportOffsets[0]);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300875 glClear(GL_COLOR_BUFFER_BIT);
876 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radevffe754b2017-07-31 10:38:07 +0300877 glDrawArrays(GL_TRIANGLES, 0, 3);
878 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
879 }
880
881 // Check second case.
882 {
Jamie Madill04c084d2018-08-08 15:49:28 -0400883 glUseProgram(singleViewProgram);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300884 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
885 1, &viewportOffsets[0]);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300886 glClear(GL_COLOR_BUFFER_BIT);
887 EXPECT_GL_NO_ERROR();
Martin Radevffe754b2017-07-31 10:38:07 +0300888 glDrawArrays(GL_TRIANGLES, 0, 3);
889 EXPECT_GL_NO_ERROR();
890 }
891
892 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
893 glDeleteQueries(1, &query);
Jamie Madill04c084d2018-08-08 15:49:28 -0400894
895 // Check starting a query after a successful draw.
896 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300897 glUseProgram(dualViewProgram);
898 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
899 2, &viewportOffsets[0]);
Jamie Madill04c084d2018-08-08 15:49:28 -0400900 glClear(GL_COLOR_BUFFER_BIT);
901 EXPECT_GL_NO_ERROR();
902 glDrawArrays(GL_TRIANGLES, 0, 3);
903 EXPECT_GL_NO_ERROR();
904
905 glGenQueriesEXT(1, &query);
906 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
907
908 glDrawArrays(GL_TRIANGLES, 0, 3);
909 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
910
911 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
912 glDrawArrays(GL_TRIANGLES, 0, 3);
913 EXPECT_GL_NO_ERROR();
914
915 glDeleteQueries(1, &query);
916 }
Martin Radevffe754b2017-07-31 10:38:07 +0300917}
918
Martin Radev8f276e22017-05-30 12:05:52 +0300919// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300920TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300921{
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300922 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +0300923 {
924 return;
925 }
926 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
927 ASSERT_GL_NO_ERROR();
928
929 checkOutput();
930}
931
932// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300933TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300934{
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300935 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +0300936 {
937 return;
938 }
939 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
940 ASSERT_GL_NO_ERROR();
941
942 checkOutput();
943}
944
945// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300946TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300947{
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300948 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +0300949 {
950 return;
951 }
952 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
953 ASSERT_GL_NO_ERROR();
954
955 checkOutput();
956}
957
958// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300959TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300960{
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300961 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +0300962 {
963 return;
964 }
965
966 const std::string vsSource =
967 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300968 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300969 "layout(num_views = 4) in;\n"
970 "in vec4 vPosition;\n"
971 "void main()\n"
972 "{\n"
973 " if (gl_ViewID_OVR == 0u) {\n"
974 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
975 " } else if (gl_ViewID_OVR == 1u) {\n"
976 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
977 " } else if (gl_ViewID_OVR == 2u) {\n"
978 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
979 " } else {\n"
980 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
981 " }"
982 " gl_Position.yzw = vPosition.yzw;\n"
983 "}\n";
984
985 const std::string fsSource =
986 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300987 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300988 "precision mediump float;\n"
989 "out vec4 col;\n"
990 "void main()\n"
991 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300992 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300993 "}\n";
994
Olli Etuaho4836acc2018-08-20 15:23:18 +0300995 updateFBOs(4, 1, 4);
Martin Radev8f276e22017-05-30 12:05:52 +0300996 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +0300997
998 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
999 ASSERT_GL_NO_ERROR();
1000
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001001 resolveMultisampledFBO();
Martin Radev8f276e22017-05-30 12:05:52 +03001002 for (int i = 0; i < 4; ++i)
1003 {
1004 for (int j = 0; j < 4; ++j)
1005 {
Martin Radev8f276e22017-05-30 12:05:52 +03001006 if (i == j)
1007 {
Martin Radev67a8a012017-09-08 13:03:52 +03001008 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +03001009 }
1010 else
1011 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001012 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +03001013 }
1014 }
1015 }
1016 EXPECT_GL_NO_ERROR();
1017}
1018
1019// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +03001020TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +03001021{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001022 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +03001023 {
1024 return;
1025 }
1026
1027 const std::string vsSource =
1028 "#version 300 es\n"
1029 "#extension GL_OVR_multiview : require\n"
1030 "layout(num_views = 2) in;\n"
1031 "in vec4 vPosition;\n"
1032 "void main()\n"
1033 "{\n"
1034 " vec4 p = vPosition;\n"
1035 " if (gl_InstanceID == 1){\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001036 " p.y = p.y * 0.5 + 0.5;\n"
Martin Radev8f276e22017-05-30 12:05:52 +03001037 " } else {\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001038 " p.y = p.y * 0.5 - 0.5;\n"
Martin Radev8f276e22017-05-30 12:05:52 +03001039 " }\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001040 " 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 +03001041 " gl_Position.yzw = p.yzw;\n"
1042 "}\n";
1043
1044 const std::string fsSource =
1045 "#version 300 es\n"
1046 "#extension GL_OVR_multiview : require\n"
1047 "precision mediump float;\n"
1048 "out vec4 col;\n"
1049 "void main()\n"
1050 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001051 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +03001052 "}\n";
1053
Martin Radev3c25ad02017-08-22 17:36:53 +03001054 const int kViewWidth = 2;
1055 const int kViewHeight = 2;
1056 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001057 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev8f276e22017-05-30 12:05:52 +03001058 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +03001059
Martin Radev67a8a012017-09-08 13:03:52 +03001060 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 2u);
Martin Radev8f276e22017-05-30 12:05:52 +03001061 ASSERT_GL_NO_ERROR();
1062
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001063 resolveMultisampledFBO();
1064
Martin Radev67a8a012017-09-08 13:03:52 +03001065 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
1066 {{255, 0}, {255, 0}}};
Martin Radev3c25ad02017-08-22 17:36:53 +03001067
1068 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +03001069 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001070 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +03001071 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001072 for (int x = 0; x < 2; ++x)
1073 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001074 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][y][x], 0,
1075 expectedGreenChannel[view][y][x]),
Martin Radev3c25ad02017-08-22 17:36:53 +03001076 GetViewColor(x, y, view));
1077 }
Martin Radev8f276e22017-05-30 12:05:52 +03001078 }
1079 }
1080}
1081
Martin Radev553590a2017-07-31 16:40:39 +03001082// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
1083// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
1084// offset of each quad are passed as separate attributes which are indexed based on the
1085// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
1086// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
1087// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
1088// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +03001089TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +03001090{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001091 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev553590a2017-07-31 16:40:39 +03001092 {
1093 return;
1094 }
1095
Corentin Wallez02cd1522018-08-22 13:46:21 +02001096 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001097 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001098 if (IsWindows() && IsD3D11())
1099 {
1100 ignoreD3D11SDKLayersWarnings();
1101 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001102
Martin Radev553590a2017-07-31 16:40:39 +03001103 const std::string &vsSource =
1104 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001105 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001106 "layout(num_views = 2) in;\n"
1107 "in vec3 vPosition;\n"
1108 "in float offsetX;\n"
1109 "in float offsetY;\n"
1110 "void main()\n"
1111 "{\n"
1112 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001113 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001114 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
1115 " gl_Position.yzw = p.yzw;\n"
1116 "}\n";
1117
1118 const std::string &fsSource =
1119 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001120 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001121 "precision mediump float;\n"
1122 "out vec4 col;\n"
1123 "void main()\n"
1124 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001125 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001126 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +03001127
1128 const int kViewWidth = 4;
1129 const int kViewHeight = 4;
1130 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001131 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev553590a2017-07-31 16:40:39 +03001132 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev553590a2017-07-31 16:40:39 +03001133
1134 GLBuffer xOffsetVBO;
1135 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1136 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
1137 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
1138 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1139 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1140 glVertexAttribDivisor(xOffsetLoc, 3);
1141 glEnableVertexAttribArray(xOffsetLoc);
1142
1143 GLBuffer yOffsetVBO;
1144 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1145 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1146 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1147 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1148 glVertexAttribDivisor(yOffsetLoc, 1);
1149 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1150 glEnableVertexAttribArray(yOffsetLoc);
1151
Martin Radev67a8a012017-09-08 13:03:52 +03001152 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev553590a2017-07-31 16:40:39 +03001153 ASSERT_GL_NO_ERROR();
1154
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001155 resolveMultisampledFBO();
1156
Martin Radev67a8a012017-09-08 13:03:52 +03001157 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001158 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1159 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1160 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +03001161 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001162 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +03001163 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001164 for (int col = 0; col < 4; ++col)
1165 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001166 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0,
1167 expectedGreenChannel[view][row][col]),
Martin Radev3c25ad02017-08-22 17:36:53 +03001168 GetViewColor(col, row, view));
1169 }
Martin Radev553590a2017-07-31 16:40:39 +03001170 }
1171 }
1172}
1173
1174// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1175// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +03001176TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +03001177{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001178 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev553590a2017-07-31 16:40:39 +03001179 {
1180 return;
1181 }
1182
Olli Etuaho4836acc2018-08-20 15:23:18 +03001183 updateFBOs(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +03001184
1185 // Create multiview program.
1186 const std::string &vs =
1187 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001188 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001189 "layout(num_views = 2) in;\n"
1190 "layout(location = 0) in vec2 vPosition;\n"
1191 "layout(location = 1) in float offsetX;\n"
1192 "void main()\n"
1193 "{\n"
1194 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1195 " p.x += offsetX;\n"
1196 " gl_Position = p;\n"
1197 "}\n";
1198
1199 const std::string &fs =
1200 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001201 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001202 "precision mediump float;\n"
1203 "out vec4 col;\n"
1204 "void main()\n"
1205 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001206 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001207 "}\n";
1208
1209 ANGLE_GL_PROGRAM(program, vs, fs);
1210
1211 const std::string &dummyVS =
1212 "#version 300 es\n"
1213 "layout(location = 0) in vec2 vPosition;\n"
1214 "layout(location = 1) in float offsetX;\n"
1215 "void main()\n"
1216 "{\n"
1217 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1218 "}\n";
1219
1220 const std::string &dummyFS =
1221 "#version 300 es\n"
1222 "precision mediump float;\n"
1223 "out vec4 col;\n"
1224 "void main()\n"
1225 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001226 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001227 "}\n";
1228
1229 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
1230
1231 GLBuffer xOffsetVBO;
1232 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1233 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1234 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1235 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1236
1237 GLBuffer vertexVBO;
1238 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1239 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1240 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1241 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1242
1243 GLVertexArray vao[2];
1244 for (size_t i = 0u; i < 2u; ++i)
1245 {
1246 glBindVertexArray(vao[i]);
1247
1248 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1249 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1250 glEnableVertexAttribArray(0);
1251
1252 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1253 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1254 glEnableVertexAttribArray(1);
1255 }
1256 ASSERT_GL_NO_ERROR();
1257
1258 glViewport(0, 0, 1, 1);
1259 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001260 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001261 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001262
1263 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1264 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1265 // bits are cleared.
1266 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001267 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1268 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001269 glBindVertexArray(vao[0]);
1270 glVertexAttribDivisor(1, 0);
1271 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1272 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001273 ASSERT_GL_NO_ERROR();
1274
1275 // Check that vertexAttribDivisor uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001276 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001277 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001278 glUseProgram(program);
1279 glVertexAttribDivisor(1, 1);
1280 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001281
1282 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001283 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1284 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001285
1286 // Clear the buffers and propagate divisor to the driver.
1287 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1288 // dirty bits when useProgram is called.
1289 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001290 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1291 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001292 glVertexAttribDivisor(1, 1);
1293 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1294 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001295 ASSERT_GL_NO_ERROR();
1296
1297 // Check that useProgram uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001298 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001299 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001300 glUseProgram(program);
1301 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001302
1303 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001304 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1305 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001306
1307 // We go through similar steps as before.
1308 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001309 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1310 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001311 glVertexAttribDivisor(1, 1);
1312 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1313 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001314 ASSERT_GL_NO_ERROR();
1315
1316 // Check that bindVertexArray uses the number of views to update the divisor.
1317 {
1318 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1319 // divisor for vao[1] only.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001320 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001321 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001322 glBindVertexArray(vao[1]);
1323 glUseProgram(program);
1324 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001325 glBindVertexArray(0);
1326 ASSERT_GL_NO_ERROR();
1327 }
1328 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1329 // adjusts the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001330 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001331 glBindVertexArray(vao[0]);
1332 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001333
1334 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001335 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1336 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001337}
1338
Martin Radev0d671c92017-08-10 16:41:52 +03001339// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1340// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001341TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001342{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001343 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1344 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001345
1346 const std::string vsSource =
1347 "#version 300 es\n"
1348 "#extension GL_OVR_multiview : require\n"
1349 "layout(num_views = 2) in;\n"
1350 "in vec3 vPosition;\n"
1351 "void main()\n"
1352 "{\n"
1353 " gl_Position.x = 2.0;\n"
1354 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1355 "}\n";
1356
1357 const std::string fsSource =
1358 "#version 300 es\n"
1359 "#extension GL_OVR_multiview : require\n"
1360 "precision mediump float;\n"
1361 "out vec4 col;\n"
1362 "void main()\n"
1363 "{\n"
1364 " col = vec4(1,0,0,0);\n"
1365 "}\n";
1366 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001367 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001368
1369 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1370 ASSERT_GL_NO_ERROR();
1371 EXPECT_GL_FALSE(result);
1372}
1373
1374// Test that there are fragments passing the occlusion query if only view 0 can produce
1375// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001376TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001377{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001378 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1379 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001380
1381 const std::string vsSource =
1382 "#version 300 es\n"
1383 "#extension GL_OVR_multiview : require\n"
1384 "layout(num_views = 2) in;\n"
1385 "in vec3 vPosition;\n"
1386 "void main()\n"
1387 "{\n"
1388 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1389 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1390 "}\n";
1391
1392 const std::string fsSource =
1393 "#version 300 es\n"
1394 "#extension GL_OVR_multiview : require\n"
1395 "precision mediump float;\n"
1396 "out vec4 col;\n"
1397 "void main()\n"
1398 "{\n"
1399 " col = vec4(1,0,0,0);\n"
1400 "}\n";
1401 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001402 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001403
1404 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1405 ASSERT_GL_NO_ERROR();
1406 EXPECT_GL_TRUE(result);
1407}
1408
1409// Test that there are fragments passing the occlusion query if only view 1 can produce
1410// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001411TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001412{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001413 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1414 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001415
1416 const std::string vsSource =
1417 "#version 300 es\n"
1418 "#extension GL_OVR_multiview : require\n"
1419 "layout(num_views = 2) in;\n"
1420 "in vec3 vPosition;\n"
1421 "void main()\n"
1422 "{\n"
1423 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1424 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1425 "}\n";
1426
1427 const std::string fsSource =
1428 "#version 300 es\n"
1429 "#extension GL_OVR_multiview : require\n"
1430 "precision mediump float;\n"
1431 "out vec4 col;\n"
1432 "void main()\n"
1433 "{\n"
1434 " col = vec4(1,0,0,0);\n"
1435 "}\n";
1436 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001437 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001438
1439 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1440 ASSERT_GL_NO_ERROR();
1441 EXPECT_GL_TRUE(result);
1442}
1443
Martin Radev41ac68e2017-06-06 12:16:58 +03001444// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1445// compiles and links without an error.
1446TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1447{
1448 if (!requestMultiviewExtension())
1449 {
1450 return;
1451 }
1452
1453 const std::string vsSource =
1454 "#version 300 es\n"
1455 "#extension GL_OVR_multiview : require\n"
1456 "layout(num_views = 2) in;\n"
1457 "void main()\n"
1458 "{\n"
1459 "}\n";
1460
1461 const std::string fsSource =
1462 "#version 300 es\n"
1463 "#extension GL_OVR_multiview : require\n"
1464 "precision mediump float;\n"
1465 "void main()\n"
1466 "{\n"
1467 "}\n";
1468
1469 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1470 glUseProgram(program);
1471
1472 EXPECT_GL_NO_ERROR();
1473}
1474
1475// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1476// without an error.
1477TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1478{
1479 if (!requestMultiviewExtension())
1480 {
1481 return;
1482 }
1483
1484 const std::string vsSource =
1485 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001486 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001487 "layout(num_views = 2) in;\n"
1488 "void main()\n"
1489 "{\n"
1490 " if (gl_ViewID_OVR == 0u) {\n"
1491 " gl_Position = vec4(1,0,0,1);\n"
1492 " } else {\n"
1493 " gl_Position = vec4(-1,0,0,1);\n"
1494 " }\n"
1495 "}\n";
1496
1497 const std::string fsSource =
1498 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001499 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001500 "precision mediump float;\n"
1501 "void main()\n"
1502 "{\n"
1503 "}\n";
1504
1505 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1506 glUseProgram(program);
1507
1508 EXPECT_GL_NO_ERROR();
1509}
1510
1511// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1512// without an error.
1513TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1514{
1515 if (!requestMultiviewExtension())
1516 {
1517 return;
1518 }
1519
1520 const std::string vsSource =
1521 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001522 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001523 "layout(num_views = 2) in;\n"
1524 "void main()\n"
1525 "{\n"
1526 "}\n";
1527
1528 const std::string fsSource =
1529 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001530 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001531 "precision mediump float;\n"
1532 "out vec4 col;\n"
1533 "void main()\n"
1534 "{\n"
1535 " if (gl_ViewID_OVR == 0u) {\n"
1536 " col = vec4(1,0,0,1);\n"
1537 " } else {\n"
1538 " col = vec4(-1,0,0,1);\n"
1539 " }\n"
1540 "}\n";
1541
1542 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1543 glUseProgram(program);
1544
1545 EXPECT_GL_NO_ERROR();
1546}
1547
Martin Radev61bd9992017-08-11 13:10:55 +03001548// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001549TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001550{
1551 if (!requestMultiviewExtension())
1552 {
1553 return;
1554 }
1555
Geoff Lang25858162017-11-06 11:25:58 -05001556 // Test failing on P400 graphics card (anglebug.com/2228)
1557 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1558
Martin Radev61bd9992017-08-11 13:10:55 +03001559 const std::string vsSource =
1560 "#version 300 es\n"
1561 "#extension GL_OVR_multiview : require\n"
1562 "layout(num_views = 2) in;\n"
1563 "layout(location=0) in vec2 vPosition;\n"
1564 "void main()\n"
1565 "{\n"
1566 " gl_PointSize = 1.0;\n"
1567 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1568 "}\n";
1569
1570 const std::string fsSource =
1571 "#version 300 es\n"
1572 "#extension GL_OVR_multiview : require\n"
1573 "precision mediump float;\n"
1574 "out vec4 col;\n"
1575 "void main()\n"
1576 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001577 " col = vec4(0,1,0,1);\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001578 "}\n";
1579 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1580 glUseProgram(program);
1581
Martin Radev3c25ad02017-08-22 17:36:53 +03001582 const int kViewWidth = 4;
1583 const int kViewHeight = 2;
1584 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001585 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001586
1587 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1588 std::vector<Vector2> vertexDataInClipSpace =
1589 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1590 setupGeometry(vertexDataInClipSpace);
1591
1592 glDrawArrays(GL_POINTS, 0, 2);
1593
Martin Radev67a8a012017-09-08 13:03:52 +03001594 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001595 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001596 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001597}
1598
1599// The test checks that GL_LINES is correctly rendered.
1600// The behavior of this test is not guaranteed by the spec:
1601// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1602// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1603// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1604// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001605TEST_P(MultiviewRenderPrimitiveTest, Lines)
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
Martin Radev3c25ad02017-08-22 17:36:53 +03001617 const int kViewWidth = 4;
1618 const int kViewHeight = 2;
1619 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001620 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001621
1622 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1623 std::vector<Vector2> vertexDataInClipSpace =
1624 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1625 setupGeometry(vertexDataInClipSpace);
1626
1627 glDrawArrays(GL_LINES, 0, 2);
1628
Martin Radev67a8a012017-09-08 13:03:52 +03001629 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001630 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001631 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001632
1633 glDeleteProgram(program);
1634}
1635
1636// The test checks that GL_LINE_STRIP is correctly rendered.
1637// The behavior of this test is not guaranteed by the spec:
1638// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1639// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1640// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1641// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001642TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001643{
1644 if (!requestMultiviewExtension())
1645 {
1646 return;
1647 }
1648
Martin Radevced5c862017-08-17 16:05:29 +03001649 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001650 ASSERT_NE(program, 0u);
1651 glUseProgram(program);
1652 ASSERT_GL_NO_ERROR();
1653
Martin Radev3c25ad02017-08-22 17:36:53 +03001654 const int kViewWidth = 4;
1655 const int kViewHeight = 2;
1656 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001657 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001658
1659 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1660 std::vector<Vector2> vertexDataInClipSpace =
1661 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1662 setupGeometry(vertexDataInClipSpace);
1663
1664 glDrawArrays(GL_LINE_STRIP, 0, 3);
1665
Martin Radev67a8a012017-09-08 13:03:52 +03001666 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001667 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001668 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001669
1670 glDeleteProgram(program);
1671}
1672
1673// The test checks that GL_LINE_LOOP is correctly rendered.
1674// The behavior of this test is not guaranteed by the spec:
1675// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1676// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1677// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1678// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001679TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001680{
1681 if (!requestMultiviewExtension())
1682 {
1683 return;
1684 }
1685
Martin Radevced5c862017-08-17 16:05:29 +03001686 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001687 ASSERT_NE(program, 0u);
1688 glUseProgram(program);
1689 ASSERT_GL_NO_ERROR();
1690
Martin Radev3c25ad02017-08-22 17:36:53 +03001691 const int kViewWidth = 4;
1692 const int kViewHeight = 4;
1693 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001694 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001695
1696 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1697 Vector2I(0, 3)};
1698 std::vector<Vector2> vertexDataInClipSpace =
1699 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1700 setupGeometry(vertexDataInClipSpace);
1701
1702 glDrawArrays(GL_LINE_LOOP, 0, 4);
1703
Martin Radev67a8a012017-09-08 13:03:52 +03001704 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001705 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1706 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001707 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001708
1709 glDeleteProgram(program);
1710}
1711
1712// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001713TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001714{
1715 if (!requestMultiviewExtension())
1716 {
1717 return;
1718 }
1719
Martin Radevced5c862017-08-17 16:05:29 +03001720 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001721 ASSERT_NE(program, 0u);
1722 glUseProgram(program);
1723 ASSERT_GL_NO_ERROR();
1724
1725 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1726 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1727 setupGeometry(vertexDataInClipSpace);
1728
Martin Radev3c25ad02017-08-22 17:36:53 +03001729 const int kViewWidth = 2;
1730 const int kViewHeight = 2;
1731 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001732 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001733
1734 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1735
Martin Radev67a8a012017-09-08 13:03:52 +03001736 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1737 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1738 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001739
1740 glDeleteProgram(program);
1741}
1742
1743// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001744TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001745{
1746 if (!requestMultiviewExtension())
1747 {
1748 return;
1749 }
1750
Martin Radevced5c862017-08-17 16:05:29 +03001751 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001752 ASSERT_NE(program, 0u);
1753 glUseProgram(program);
1754 ASSERT_GL_NO_ERROR();
1755
1756 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1757 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1758 setupGeometry(vertexDataInClipSpace);
1759
Martin Radev3c25ad02017-08-22 17:36:53 +03001760 const int kViewWidth = 2;
1761 const int kViewHeight = 2;
1762 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001763 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001764
1765 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1766
Martin Radev67a8a012017-09-08 13:03:52 +03001767 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1768 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1769 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001770
1771 glDeleteProgram(program);
1772}
1773
1774// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1775// bounds. The test does not rely on the actual line width being greater than 1.0.
Martin Radev3c25ad02017-08-22 17:36:53 +03001776TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
Martin Radev61bd9992017-08-11 13:10:55 +03001777{
1778 if (!requestMultiviewExtension())
1779 {
1780 return;
1781 }
1782
Olli Etuaho9259fd02018-08-22 12:12:00 +03001783 GLTexture colorTexture;
Martin Radev61bd9992017-08-11 13:10:55 +03001784
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001785 CreateMultiviewBackingTextures(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, 0, 2, 1, 2,
Olli Etuaho9259fd02018-08-22 12:12:00 +03001786 colorTexture, 0u, 0u);
1787
1788 GLFramebuffer drawFramebuffer;
1789 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFramebuffer);
Martin Radev61bd9992017-08-11 13:10:55 +03001790 GLint viewportOffsets[4] = {1, 0, 3, 0};
1791 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
Olli Etuaho9259fd02018-08-22 12:12:00 +03001792 colorTexture, 0, 2, &viewportOffsets[0]);
1793
1794 GLFramebuffer readFramebuffer;
1795 glBindFramebuffer(GL_READ_FRAMEBUFFER, readFramebuffer);
1796 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture,
1797 0);
1798
1799 ASSERT_GL_NO_ERROR();
Martin Radev61bd9992017-08-11 13:10:55 +03001800
1801 glViewport(0, 0, 1, 1);
1802 glScissor(0, 0, 1, 1);
1803 glEnable(GL_SCISSOR_TEST);
1804
1805 const std::string vsSource =
1806 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001807 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001808 "layout(num_views = 2) in;\n"
1809 "layout(location=0) in vec2 vPosition;\n"
1810 "void main()\n"
1811 "{\n"
1812 " gl_PointSize = 10.0;\n"
1813 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1814 "}\n";
1815
1816 const std::string fsSource =
1817 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001818 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001819 "precision mediump float;\n"
1820 "out vec4 col;\n"
1821 "void main()\n"
1822 "{\n"
1823 " if (gl_ViewID_OVR == 0u) {\n"
1824 " col = vec4(1,0,0,1);\n"
1825 " } else {\n"
1826 " col = vec4(0,1,0,1);\n"
1827 " }\n"
1828 "}\n";
1829 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1830 glUseProgram(program);
1831
1832 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1833 const std::vector<Vector2> &vertexDataInClipSpace =
1834 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001835
1836 GLBuffer vbo;
1837 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1838 glBufferData(GL_ARRAY_BUFFER, vertexDataInClipSpace.size() * sizeof(Vector2),
1839 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1840 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -05001841 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +03001842
1843 // Test rendering points.
1844 {
1845 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1846 glDrawArrays(GL_POINTS, 0, 2);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001847 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001848 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001849 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001850 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1851 }
1852
1853 // Test rendering lines.
1854 {
1855 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1856 glLineWidth(10.f);
1857 glDrawArrays(GL_LINES, 0, 2);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001858 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001859 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001860 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001861 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1862 }
1863}
1864
Martin Radev0abb7a22017-08-28 15:34:45 +03001865// Verify that re-linking a program adjusts the attribute divisor.
1866// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1867// to each other. The quads' position and color depend on the corresponding attribute divisors.
1868TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1869{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001870 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev0abb7a22017-08-28 15:34:45 +03001871 {
1872 return;
1873 }
1874
Corentin Wallez02cd1522018-08-22 13:46:21 +02001875 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001876 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001877 if (IsWindows() && IsD3D11())
1878 {
1879 ignoreD3D11SDKLayersWarnings();
1880 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001881
Martin Radev0abb7a22017-08-28 15:34:45 +03001882 const int kViewWidth = 4;
1883 const int kViewHeight = 1;
1884 const int kNumViews = 2;
1885
1886 const std::string &fsSource =
1887 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001888 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001889 "precision mediump float;\n"
1890 "in vec4 oColor;\n"
1891 "out vec4 col;\n"
1892 "void main()\n"
1893 "{\n"
1894 " col = oColor;\n"
1895 "}\n";
1896
1897 auto generateVertexShaderSource = [](int numViews) -> std::string {
1898 std::string source =
1899 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001900 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001901 "layout(num_views = " +
1902 ToString(numViews) +
1903 ") in;\n"
1904 "in vec3 vPosition;\n"
1905 "in float vOffsetX;\n"
1906 "in vec4 vColor;\n"
1907 "out vec4 oColor;\n"
1908 "void main()\n"
1909 "{\n"
1910 " vec4 p = vec4(vPosition, 1.);\n"
1911 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1912 " oColor = vColor;\n"
1913 " gl_Position = p;\n"
1914 "}\n";
1915 return source;
1916 };
1917
1918 std::string vsSource = generateVertexShaderSource(kNumViews);
1919 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1920 glUseProgram(program);
1921
1922 GLint positionLoc;
1923 GLBuffer xOffsetVBO;
1924 GLint xOffsetLoc;
1925 GLBuffer colorVBO;
1926 GLint colorLoc;
1927
1928 {
1929 // Initialize buffers and setup attributes.
1930 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1931 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1932 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1933 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1934 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1935 glVertexAttribDivisor(xOffsetLoc, 1);
1936 glEnableVertexAttribArray(xOffsetLoc);
1937
1938 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1939 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1940 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1941 colorLoc = glGetAttribLocation(program, "vColor");
1942 glVertexAttribDivisor(colorLoc, 2);
1943 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1944 glEnableVertexAttribArray(colorLoc);
1945
1946 positionLoc = glGetAttribLocation(program, "vPosition");
1947 }
1948
1949 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001950 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001951
Martin Radev67a8a012017-09-08 13:03:52 +03001952 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001953 ASSERT_GL_NO_ERROR();
1954
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001955 resolveMultisampledFBO();
Martin Radev0abb7a22017-08-28 15:34:45 +03001956 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1957 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1958 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1959 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1960 }
1961
1962 {
1963 const int kNewNumViews = 3;
1964 vsSource = generateVertexShaderSource(kNewNumViews);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001965 updateFBOs(kViewWidth, kViewHeight, kNewNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001966
1967 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
1968 ASSERT_NE(0u, vs);
1969 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
1970 ASSERT_NE(0u, fs);
1971
1972 GLint numAttachedShaders = 0;
1973 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1974
1975 GLuint attachedShaders[2] = {0u};
1976 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1977 for (int i = 0; i < 2; ++i)
1978 {
1979 glDetachShader(program, attachedShaders[i]);
1980 }
1981
1982 glAttachShader(program, vs);
1983 glDeleteShader(vs);
1984
1985 glAttachShader(program, fs);
1986 glDeleteShader(fs);
1987
1988 glBindAttribLocation(program, positionLoc, "vPosition");
1989 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1990 glBindAttribLocation(program, colorLoc, "vColor");
1991
1992 glLinkProgram(program);
1993
Martin Radev67a8a012017-09-08 13:03:52 +03001994 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001995 ASSERT_GL_NO_ERROR();
1996
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001997 resolveMultisampledFBO();
Martin Radev0abb7a22017-08-28 15:34:45 +03001998 for (int i = 0; i < kNewNumViews; ++i)
1999 {
2000 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
2001 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
2002 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
2003 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
2004 }
2005 }
2006}
2007
Martin Radevced5c862017-08-17 16:05:29 +03002008// Test that useProgram applies the number of views in computing the final value of the attribute
2009// divisor.
2010TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
2011{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002012 if (!requestMultiviewExtension(isMultisampled()))
Martin Radevced5c862017-08-17 16:05:29 +03002013 {
2014 return;
2015 }
2016
Geoff Lang25858162017-11-06 11:25:58 -05002017 // Test failing on P400 graphics card (anglebug.com/2228)
2018 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
2019
Olli Etuaho44ae8992018-08-20 15:37:09 +03002020 // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
2021 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03002022 if (IsWindows() && IsD3D11())
2023 {
2024 ignoreD3D11SDKLayersWarnings();
2025 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03002026
Martin Radevced5c862017-08-17 16:05:29 +03002027 GLVertexArray vao;
2028 glBindVertexArray(vao);
2029 GLBuffer vbo;
2030 glBindBuffer(GL_ARRAY_BUFFER, vbo);
2031 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
2032 Vector2I(3, 0)};
2033 std::vector<Vector2> vertexDataInClipSpace =
2034 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
2035 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
2036 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
2037 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
2038 glEnableVertexAttribArray(0);
2039 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
2040 glVertexAttribDivisor(0, 1);
2041 ASSERT_GL_NO_ERROR();
2042
2043 // Create a program and fbo with N views and draw N instances of a point horizontally.
2044 for (int numViews = 2; numViews <= 4; ++numViews)
2045 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03002046 updateFBOs(4, 1, numViews);
Martin Radevced5c862017-08-17 16:05:29 +03002047 ASSERT_GL_NO_ERROR();
2048
2049 GLuint program = CreateSimplePassthroughProgram(numViews);
2050 ASSERT_NE(program, 0u);
2051 glUseProgram(program);
2052 ASSERT_GL_NO_ERROR();
2053
2054 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
2055
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002056 resolveMultisampledFBO();
Martin Radevced5c862017-08-17 16:05:29 +03002057 for (int view = 0; view < numViews; ++view)
2058 {
2059 for (int j = 0; j < numViews; ++j)
2060 {
Martin Radev67a8a012017-09-08 13:03:52 +03002061 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03002062 }
2063 for (int j = numViews; j < 4; ++j)
2064 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03002065 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03002066 }
2067 }
2068
2069 glDeleteProgram(program);
2070 }
2071}
2072
Martin Radev72b4e1e2017-08-31 15:42:56 +03002073// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
2074TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
2075{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002076 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev72b4e1e2017-08-31 15:42:56 +03002077 {
2078 return;
2079 }
2080
2081 const std::string vsSource =
2082 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002083 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002084 "layout(num_views = 3) in;\n"
2085 "in vec3 vPosition;\n"
2086 "void main()\n"
2087 "{\n"
2088 " gl_Position = vec4(vPosition, 1.);\n"
2089 "}\n";
2090
2091 const std::string fsSource =
2092 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002093 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002094 "precision mediump float;\n"
2095 "out vec4 col;\n"
2096 "void main()\n"
2097 "{\n"
2098 " if (gl_ViewID_OVR == 0u) {\n"
2099 " col = vec4(1,0,0,1);\n"
2100 " } else if (gl_ViewID_OVR == 1u) {\n"
2101 " col = vec4(0,1,0,1);\n"
2102 " } else if (gl_ViewID_OVR == 2u) {\n"
2103 " col = vec4(0,0,1,1);\n"
2104 " } else {\n"
2105 " col = vec4(0,0,0,0);\n"
2106 " }\n"
2107 "}\n";
2108
Olli Etuaho4836acc2018-08-20 15:23:18 +03002109 updateFBOs(1, 1, 3);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002110 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002111
2112 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2113 ASSERT_GL_NO_ERROR();
2114
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002115 resolveMultisampledFBO();
Martin Radev72b4e1e2017-08-31 15:42:56 +03002116 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2117 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2118 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
2119}
2120
2121// The test checks that the inactive layers of a 2D texture array are not written to by a
2122// multi-view program.
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002123TEST_P(MultiviewLayeredRenderTest, RenderToSubrangeOfLayers)
Martin Radev72b4e1e2017-08-31 15:42:56 +03002124{
2125 if (!requestMultiviewExtension())
2126 {
2127 return;
2128 }
2129
2130 const std::string vsSource =
2131 "#version 300 es\n"
2132 "#extension GL_OVR_multiview : require\n"
2133 "layout(num_views = 2) in;\n"
2134 "in vec3 vPosition;\n"
2135 "void main()\n"
2136 "{\n"
2137 " gl_Position = vec4(vPosition, 1.);\n"
2138 "}\n";
2139
2140 const std::string fsSource =
2141 "#version 300 es\n"
2142 "#extension GL_OVR_multiview : require\n"
2143 "precision mediump float;\n"
2144 "out vec4 col;\n"
2145 "void main()\n"
2146 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002147 " col = vec4(0,1,0,1);\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002148 "}\n";
2149
Olli Etuaho4836acc2018-08-20 15:23:18 +03002150 updateFBOs(1, 1, 2, 4, 1);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002151 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002152
2153 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2154 ASSERT_GL_NO_ERROR();
2155
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002156 resolveMultisampledFBO();
Martin Radev72b4e1e2017-08-31 15:42:56 +03002157 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +03002158 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2159 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002160 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
2161}
2162
Martin Radevc1d4e552017-08-21 12:01:10 +03002163// The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
2164// potential bugs if the view is selected in the VS. The test contains a program in which the
2165// gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
2166// fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
2167// never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
2168// green for view 1.
2169TEST_P(MultiviewRenderTest, FlatInterpolation)
Martin Radev3c25ad02017-08-22 17:36:53 +03002170{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002171 if (!requestMultiviewExtension(isMultisampled()))
Martin Radevc1d4e552017-08-21 12:01:10 +03002172 {
2173 return;
2174 }
2175
2176 const std::string vsSource =
2177 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002178 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002179 "layout(num_views = 2) in;\n"
2180 "in vec3 vPosition;\n"
2181 "flat out int oInstanceID;\n"
2182 "void main()\n"
2183 "{\n"
2184 " gl_Position = vec4(vPosition, 1.);\n"
2185 " oInstanceID = gl_InstanceID;\n"
2186 "}\n";
2187
2188 const std::string fsSource =
2189 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002190 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002191 "precision mediump float;\n"
2192 "flat in int oInstanceID;\n"
2193 "out vec4 col;\n"
2194 "void main()\n"
2195 "{\n"
2196 " if (oInstanceID < 0) {\n"
2197 " discard;\n"
2198 " }\n"
2199 " if (gl_ViewID_OVR == 0u) {\n"
2200 " col = vec4(1,0,0,1);\n"
2201 " } else {\n"
2202 " col = vec4(0,1,0,1);\n"
2203 " }\n"
2204 "}\n";
2205
Olli Etuaho4836acc2018-08-20 15:23:18 +03002206 updateFBOs(1, 1, 2);
Martin Radevc1d4e552017-08-21 12:01:10 +03002207 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2208
2209 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2210 ASSERT_GL_NO_ERROR();
2211
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002212 resolveMultisampledFBO();
Martin Radevc1d4e552017-08-21 12:01:10 +03002213 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2214 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +03002215}
2216
Olli Etuaho604d8732018-07-20 11:02:43 +03002217// This test assigns gl_ViewID_OVR to a flat int varying and then sets the color based on that
2218// varying in the fragment shader.
2219TEST_P(MultiviewRenderTest, FlatInterpolation2)
2220{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002221 if (!requestMultiviewExtension(isMultisampled()))
Olli Etuaho604d8732018-07-20 11:02:43 +03002222 {
2223 return;
2224 }
2225
2226 const std::string vsSource =
2227 "#version 300 es\n"
2228 "#extension GL_OVR_multiview : require\n"
2229 "layout(num_views = 2) in;\n"
2230 "in vec3 vPosition;\n"
2231 "flat out int flatVarying;\n"
2232 "void main()\n"
2233 "{\n"
2234 " gl_Position = vec4(vPosition, 1.);\n"
2235 " flatVarying = int(gl_ViewID_OVR);\n"
2236 "}\n";
2237
2238 const std::string fsSource =
2239 "#version 300 es\n"
2240 "#extension GL_OVR_multiview : require\n"
2241 "precision mediump float;\n"
2242 "flat in int flatVarying;\n"
2243 "out vec4 col;\n"
2244 "void main()\n"
2245 "{\n"
2246 " if (flatVarying == 0) {\n"
2247 " col = vec4(1,0,0,1);\n"
2248 " } else {\n"
2249 " col = vec4(0,1,0,1);\n"
2250 " }\n"
2251 "}\n";
2252
Olli Etuaho4836acc2018-08-20 15:23:18 +03002253 updateFBOs(1, 1, 2);
Olli Etuaho604d8732018-07-20 11:02:43 +03002254 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2255
2256 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2257 ASSERT_GL_NO_ERROR();
2258
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002259 resolveMultisampledFBO();
Olli Etuaho604d8732018-07-20 11:02:43 +03002260 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2261 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2262}
2263
Martin Radev265a6d42017-09-12 16:51:37 +03002264// The test is added to cover a bug which resulted in the viewport/scissor and viewport offsets not
2265// being correctly applied.
2266TEST_P(MultiviewSideBySideRenderTest, ViewportOffsetsAppliedBugCoverage)
2267{
2268 if (!requestMultiviewExtension())
2269 {
2270 return;
2271 }
2272
Olli Etuaho4836acc2018-08-20 15:23:18 +03002273 updateFBOs(1, 1, 2);
Martin Radev265a6d42017-09-12 16:51:37 +03002274
2275 // Create multiview program.
2276 const std::string &vs =
2277 "#version 300 es\n"
2278 "#extension GL_OVR_multiview : require\n"
2279 "layout(num_views = 2) in;\n"
2280 "layout(location = 0) in vec3 vPosition;\n"
2281 "void main()\n"
2282 "{\n"
2283 " gl_Position = vec4(vPosition, 1.0);\n"
2284 "}\n";
2285
2286 const std::string &fs =
2287 "#version 300 es\n"
2288 "#extension GL_OVR_multiview : require\n"
2289 "precision mediump float;\n"
2290 "out vec4 col;\n"
2291 "void main()\n"
2292 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002293 " col = vec4(0,1,0,1);\n"
Martin Radev265a6d42017-09-12 16:51:37 +03002294 "}\n";
2295
2296 ANGLE_GL_PROGRAM(program, vs, fs);
2297
2298 glViewport(0, 0, 1, 1);
2299 glScissor(0, 0, 1, 1);
2300 glEnable(GL_SCISSOR_TEST);
2301 glClearColor(0, 0, 0, 1);
2302
2303 // Bind the default FBO and make sure that the state is synchronized.
2304 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
2305 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2306 ASSERT_GL_NO_ERROR();
2307
2308 // Draw and check that both views are rendered to.
Olli Etuaho4836acc2018-08-20 15:23:18 +03002309 bindMemberDrawFramebuffer();
Martin Radev265a6d42017-09-12 16:51:37 +03002310 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev67a8a012017-09-08 13:03:52 +03002311
Martin Radev265a6d42017-09-12 16:51:37 +03002312 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
Martin Radev67a8a012017-09-08 13:03:52 +03002313 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
2314 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev265a6d42017-09-12 16:51:37 +03002315}
2316
Olli Etuahof26b27e2018-08-17 11:01:19 +03002317MultiviewRenderTestParams SideBySideVertexShaderOpenGL(GLint majorVersion = 3,
2318 GLint minorVersion = 0)
Martin Radev3c25ad02017-08-22 17:36:53 +03002319{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002320 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, 0,
Olli Etuahof26b27e2018-08-17 11:01:19 +03002321 VertexShaderOpenGL(majorVersion, minorVersion));
Martin Radev3c25ad02017-08-22 17:36:53 +03002322}
2323
Olli Etuahof26b27e2018-08-17 11:01:19 +03002324MultiviewRenderTestParams LayeredVertexShaderOpenGL()
Martin Radev3c25ad02017-08-22 17:36:53 +03002325{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002326 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, 0,
Olli Etuahof26b27e2018-08-17 11:01:19 +03002327 VertexShaderOpenGL(3, 0));
Martin Radev3c25ad02017-08-22 17:36:53 +03002328}
2329
Olli Etuahof26b27e2018-08-17 11:01:19 +03002330MultiviewRenderTestParams SideBySideGeomShaderD3D11()
Martin Radev72b4e1e2017-08-31 15:42:56 +03002331{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002332 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, 0,
Olli Etuahof26b27e2018-08-17 11:01:19 +03002333 GeomShaderD3D11(3, 0));
Martin Radevc1d4e552017-08-21 12:01:10 +03002334}
2335
Olli Etuahof26b27e2018-08-17 11:01:19 +03002336MultiviewRenderTestParams LayeredGeomShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002337{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002338 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, 0,
2339 GeomShaderD3D11(3, 0));
Martin Radevc1d4e552017-08-21 12:01:10 +03002340}
2341
Olli Etuahof26b27e2018-08-17 11:01:19 +03002342MultiviewRenderTestParams SideBySideVertexShaderD3D11(GLint majorVersion = 3,
2343 GLint minorVersion = 0)
Martin Radevc1d4e552017-08-21 12:01:10 +03002344{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002345 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, 0,
Olli Etuahof26b27e2018-08-17 11:01:19 +03002346 VertexShaderD3D11(majorVersion, minorVersion));
Martin Radevc1d4e552017-08-21 12:01:10 +03002347}
2348
Olli Etuahof26b27e2018-08-17 11:01:19 +03002349MultiviewRenderTestParams LayeredVertexShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002350{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002351 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, 0,
Olli Etuahof26b27e2018-08-17 11:01:19 +03002352 VertexShaderD3D11(3, 0));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002353}
2354
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002355MultiviewRenderTestParams LayeredMultisampledVertexShaderOpenGL()
2356{
2357 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, 2,
2358 VertexShaderOpenGL(3, 1));
2359}
2360
2361MultiviewRenderTestParams LayeredMultisampledVertexShaderD3D11()
2362{
2363 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, 2,
2364 VertexShaderD3D11(3, 1));
2365}
2366
Jamie Madill04c084d2018-08-08 15:49:28 -04002367ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest,
Olli Etuaho44ae8992018-08-20 15:37:09 +03002368 VertexShaderOpenGL(3, 1),
2369 VertexShaderD3D11(3, 1));
Martin Radevced5c862017-08-17 16:05:29 +03002370ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002371 SideBySideVertexShaderOpenGL(),
2372 LayeredVertexShaderOpenGL(),
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002373 LayeredMultisampledVertexShaderOpenGL(),
Martin Radevc1d4e552017-08-21 12:01:10 +03002374 SideBySideGeomShaderD3D11(),
2375 SideBySideVertexShaderD3D11(),
2376 LayeredGeomShaderD3D11(),
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002377 LayeredVertexShaderD3D11(),
2378 LayeredMultisampledVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002379ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002380 SideBySideVertexShaderOpenGL(),
2381 LayeredVertexShaderOpenGL(),
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002382 LayeredMultisampledVertexShaderOpenGL(),
Martin Radevc1d4e552017-08-21 12:01:10 +03002383 SideBySideGeomShaderD3D11(),
2384 SideBySideVertexShaderD3D11(),
2385 LayeredGeomShaderD3D11(),
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002386 LayeredVertexShaderD3D11(),
2387 LayeredMultisampledVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002388ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002389 SideBySideVertexShaderOpenGL(),
2390 LayeredVertexShaderOpenGL(),
2391 SideBySideGeomShaderD3D11(),
2392 SideBySideVertexShaderD3D11(),
2393 LayeredGeomShaderD3D11(),
2394 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002395ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
Olli Etuaho4bcaf992018-08-17 17:18:28 +03002396 VertexShaderOpenGL(3, 0),
2397 GeomShaderD3D11(3, 0),
2398 VertexShaderD3D11(3, 0));
Martin Radevced5c862017-08-17 16:05:29 +03002399ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002400 SideBySideVertexShaderOpenGL(),
2401 LayeredVertexShaderOpenGL(),
2402 SideBySideGeomShaderD3D11(),
2403 SideBySideVertexShaderD3D11(),
2404 LayeredGeomShaderD3D11(),
2405 LayeredVertexShaderD3D11());
Jamie Madill04c084d2018-08-08 15:49:28 -04002406ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest,
2407 VertexShaderOpenGL(3, 0),
2408 GeomShaderD3D11(3, 0));
2409ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, VertexShaderOpenGL(3, 0), GeomShaderD3D11(3, 0));