blob: 915ca28278e7d50dbdf6a3d154c0c42967b0274a [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)
Martin Radev8f276e22017-05-30 12:05:52 +030092 {
Martin Radev3c25ad02017-08-22 17:36:53 +030093 }
Olli Etuaho44ae8992018-08-20 15:37:09 +030094
Olli Etuaho4836acc2018-08-20 15:23:18 +030095 void FramebufferTestSetUp() { MultiviewTestBase::MultiviewTestBaseSetUp(); }
Olli Etuaho44ae8992018-08-20 15:37:09 +030096
97 void FramebufferTestTearDown()
98 {
99 freeFBOs();
100 MultiviewTestBase::MultiviewTestBaseTearDown();
101 }
102
Olli Etuaho4836acc2018-08-20 15:23:18 +0300103 void updateFBOs(int viewWidth, int height, int numViews, int numLayers, int baseViewIndex)
Martin Radev3c25ad02017-08-22 17:36:53 +0300104 {
Martin Radev72b4e1e2017-08-31 15:42:56 +0300105 ASSERT(numViews + baseViewIndex <= numLayers);
106
Olli Etuaho44ae8992018-08-20 15:37:09 +0300107 freeFBOs();
108
Martin Radev3c25ad02017-08-22 17:36:53 +0300109 mViewWidth = viewWidth;
110 mViewHeight = height;
111 mNumViews = numViews;
Martin Radev8f276e22017-05-30 12:05:52 +0300112
Olli Etuaho44ae8992018-08-20 15:37:09 +0300113 glGenTextures(1, &mColorTexture);
114 glGenTextures(1, &mDepthTexture);
Martin Radev0abb7a22017-08-28 15:34:45 +0300115
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300116 CreateMultiviewBackingTextures(mMultiviewLayout, mSamples, viewWidth, height, numLayers,
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300117 mColorTexture, mDepthTexture, 0u);
Martin Radev3c25ad02017-08-22 17:36:53 +0300118
Olli Etuaho44ae8992018-08-20 15:37:09 +0300119 glGenFramebuffers(1, &mDrawFramebuffer);
120
Martin Radev3c25ad02017-08-22 17:36:53 +0300121 // Create draw framebuffer to be used for multiview rendering.
122 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300123 AttachMultiviewTextures(GL_DRAW_FRAMEBUFFER, mMultiviewLayout, viewWidth, numViews,
124 baseViewIndex, mColorTexture, mDepthTexture, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300125
Martin Radev8f276e22017-05-30 12:05:52 +0300126 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
127
128 // Create read framebuffer to be used to retrieve the pixel information for testing
129 // purposes.
Martin Radev3c25ad02017-08-22 17:36:53 +0300130 switch (mMultiviewLayout)
131 {
132 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
133 mReadFramebuffer.resize(1);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300134 glGenFramebuffers(1, mReadFramebuffer.data());
Martin Radev3c25ad02017-08-22 17:36:53 +0300135 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
136 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
137 mColorTexture, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300138 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
139 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300140 break;
141 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
Martin Radev72b4e1e2017-08-31 15:42:56 +0300142 mReadFramebuffer.resize(numLayers);
Shahbaz Youssefic4097442018-08-22 12:14:52 -0400143 glGenFramebuffers(static_cast<GLsizei>(mReadFramebuffer.size()),
144 mReadFramebuffer.data());
Martin Radev72b4e1e2017-08-31 15:42:56 +0300145 for (int i = 0; i < numLayers; ++i)
Martin Radev3c25ad02017-08-22 17:36:53 +0300146 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300147 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
148 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
149 mColorTexture, 0, i);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300150 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
151 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300152 }
153 break;
154 default:
155 UNREACHABLE();
156 }
Martin Radev8f276e22017-05-30 12:05:52 +0300157
158 // Clear the buffers.
Martin Radev3c25ad02017-08-22 17:36:53 +0300159 glViewport(0, 0, viewWidth, height);
160 if (mMultiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
161 {
162 // Enable the scissor test only for side-by-side framebuffers.
163 glEnable(GL_SCISSOR_TEST);
164 glScissor(0, 0, viewWidth, height);
165 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300166 }
Martin Radev8f276e22017-05-30 12:05:52 +0300167
Olli Etuaho4836acc2018-08-20 15:23:18 +0300168 void updateFBOs(int viewWidth, int height, int numViews)
Martin Radev72b4e1e2017-08-31 15:42:56 +0300169 {
Olli Etuaho4836acc2018-08-20 15:23:18 +0300170 updateFBOs(viewWidth, height, numViews, numViews, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300171 }
172
Olli Etuaho4836acc2018-08-20 15:23:18 +0300173 void bindMemberDrawFramebuffer() { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer); }
174
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300175 // In case we have a multisampled framebuffer, creates and binds a resolve framebuffer as the
176 // draw framebuffer, and resolves the read framebuffer to it.
177 void resolveMultisampledFBO()
178 {
179 if (mSamples == 0)
180 {
181 return;
182 }
183 int numLayers = mReadFramebuffer.size();
184 if (mResolveFramebuffer.empty())
185 {
186 ASSERT(mResolveTexture == 0u);
187 glGenTextures(1, &mResolveTexture);
188 CreateMultiviewBackingTextures(mMultiviewLayout, 0, mViewWidth, mViewHeight, numLayers,
189 mResolveTexture, 0u, 0u);
190
191 mResolveFramebuffer.resize(numLayers);
192 glGenFramebuffers(static_cast<GLsizei>(mResolveFramebuffer.size()),
193 mResolveFramebuffer.data());
194 for (int i = 0; i < numLayers; ++i)
195 {
196 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFramebuffer[i]);
197 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
198 mResolveTexture, 0, i);
199 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
200 glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
201 }
202 }
203 for (int i = 0; i < numLayers; ++i)
204 {
205 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
206 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFramebuffer[i]);
207 glBlitFramebuffer(0, 0, mViewWidth, mViewHeight, 0, 0, mViewWidth, mViewHeight,
208 GL_COLOR_BUFFER_BIT, GL_NEAREST);
209 }
210 }
211
Martin Radev3c25ad02017-08-22 17:36:53 +0300212 GLColor GetViewColor(int x, int y, int view)
213 {
214 switch (mMultiviewLayout)
215 {
216 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300217 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
Martin Radev3c25ad02017-08-22 17:36:53 +0300218 return ReadColor(view * mViewWidth + x, y);
219 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
220 ASSERT(static_cast<size_t>(view) < mReadFramebuffer.size());
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300221 if (mSamples > 0)
222 {
223 ASSERT(static_cast<size_t>(view) < mResolveFramebuffer.size());
224 glBindFramebuffer(GL_READ_FRAMEBUFFER, mResolveFramebuffer[view]);
225 }
226 else
227 {
228 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
229 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300230 return ReadColor(x, y);
231 default:
232 UNREACHABLE();
233 }
234 return GLColor(0, 0, 0, 0);
Martin Radev8f276e22017-05-30 12:05:52 +0300235 }
236
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300237 bool isMultisampled() { return mSamples > 0; }
238
Martin Radev3c25ad02017-08-22 17:36:53 +0300239 int mViewWidth;
240 int mViewHeight;
241 int mNumViews;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300242
Olli Etuaho44ae8992018-08-20 15:37:09 +0300243 GLuint mColorTexture;
244 GLuint mDepthTexture;
245
Olli Etuaho4836acc2018-08-20 15:23:18 +0300246 private:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300247 GLuint mDrawFramebuffer;
248 std::vector<GLuint> mReadFramebuffer;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300249 GLenum mMultiviewLayout;
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300250 int mSamples;
251
252 // For reading back multisampled framebuffer.
253 std::vector<GLuint> mResolveFramebuffer;
254 GLuint mResolveTexture;
Olli Etuaho44ae8992018-08-20 15:37:09 +0300255
256 void freeFBOs()
257 {
258 if (mDrawFramebuffer)
259 {
260 glDeleteFramebuffers(1, &mDrawFramebuffer);
261 mDrawFramebuffer = 0;
262 }
263 if (!mReadFramebuffer.empty())
264 {
Shahbaz Youssefic4097442018-08-22 12:14:52 -0400265 GLsizei framebufferCount = static_cast<GLsizei>(mReadFramebuffer.size());
266 glDeleteFramebuffers(framebufferCount, mReadFramebuffer.data());
Olli Etuaho44ae8992018-08-20 15:37:09 +0300267 mReadFramebuffer.clear();
268 }
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300269 if (!mResolveFramebuffer.empty())
270 {
271 GLsizei framebufferCount = static_cast<GLsizei>(mResolveFramebuffer.size());
272 glDeleteFramebuffers(framebufferCount, mResolveFramebuffer.data());
273 mResolveFramebuffer.clear();
274 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300275 if (mDepthTexture)
276 {
277 glDeleteTextures(1, &mDepthTexture);
278 mDepthTexture = 0;
279 }
280 if (mColorTexture)
281 {
282 glDeleteTextures(1, &mColorTexture);
283 mColorTexture = 0;
284 }
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300285 if (mResolveTexture)
286 {
287 glDeleteTextures(1, &mResolveTexture);
288 mResolveTexture = 0;
289 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300290 }
Martin Radev8f276e22017-05-30 12:05:52 +0300291};
292
Olli Etuaho4836acc2018-08-20 15:23:18 +0300293class MultiviewRenderTest : public MultiviewFramebufferTestBase,
Olli Etuahof26b27e2018-08-17 11:01:19 +0300294 public ::testing::TestWithParam<MultiviewRenderTestParams>
Martin Radev8f276e22017-05-30 12:05:52 +0300295{
296 protected:
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300297 MultiviewRenderTest()
298 : MultiviewFramebufferTestBase(GetParam(), GetParam().mMultiviewLayout, GetParam().mSamples)
299 {
300 }
Olli Etuaho4836acc2018-08-20 15:23:18 +0300301 void SetUp() override { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300302 void TearDown() override { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
Martin Radevc1d4e552017-08-21 12:01:10 +0300303
304 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
305 {
306 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
307 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300308};
309
Jamie Madill04c084d2018-08-08 15:49:28 -0400310constexpr char kDualViewVSSource[] = R"(#version 300 es
311#extension GL_OVR_multiview : require
312layout(num_views = 2) in;
313in vec4 vPosition;
314void main()
315{
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300316 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 -0400317 gl_Position.yzw = vPosition.yzw;
318})";
319
320constexpr char kDualViewFSSource[] = R"(#version 300 es
321#extension GL_OVR_multiview : require
322precision mediump float;
323out vec4 col;
324void main()
325{
326 col = vec4(0,1,0,1);
327})";
328
Martin Radev3c25ad02017-08-22 17:36:53 +0300329class MultiviewRenderDualViewTest : public MultiviewRenderTest
330{
331 protected:
332 MultiviewRenderDualViewTest() : mProgram(0u) {}
Martin Radev8f276e22017-05-30 12:05:52 +0300333
334 void SetUp() override
335 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300336 MultiviewRenderTest::SetUp();
Martin Radev8f276e22017-05-30 12:05:52 +0300337
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300338 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +0300339 {
340 return;
341 }
342
Olli Etuaho4836acc2018-08-20 15:23:18 +0300343 updateFBOs(2, 1, 2);
Jamie Madill04c084d2018-08-08 15:49:28 -0400344 mProgram = CompileProgram(kDualViewVSSource, kDualViewFSSource);
Martin Radev61bd9992017-08-11 13:10:55 +0300345 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300346 glUseProgram(mProgram);
347 ASSERT_GL_NO_ERROR();
348 }
349
Olli Etuaho44ae8992018-08-20 15:37:09 +0300350 void TearDown() override
351 {
352 if (mProgram != 0u)
353 {
354 glDeleteProgram(mProgram);
355 mProgram = 0u;
356 }
357
358 MultiviewRenderTest::TearDown();
359 }
360
Martin Radev8f276e22017-05-30 12:05:52 +0300361 void checkOutput()
362 {
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300363 resolveMultisampledFBO();
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300364 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +0300365 EXPECT_EQ(GLColor::green, GetViewColor(1, 0, 0));
366 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300367 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(1, 0, 1));
Martin Radev8f276e22017-05-30 12:05:52 +0300368 }
369
370 GLuint mProgram;
371};
372
Olli Etuaho44ae8992018-08-20 15:37:09 +0300373// Base class for tests that care mostly about draw call validity and not rendering results.
374class MultiviewDrawValidationTest : public MultiviewTest
Jamie Madill04c084d2018-08-08 15:49:28 -0400375{
376 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300377 MultiviewDrawValidationTest() : MultiviewTest() {}
Jamie Madill04c084d2018-08-08 15:49:28 -0400378
Olli Etuaho44ae8992018-08-20 15:37:09 +0300379 void initOnePixelColorTexture2D(GLuint texId)
Jamie Madill04c084d2018-08-08 15:49:28 -0400380 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300381 glBindTexture(GL_TEXTURE_2D, texId);
Jamie Madill04c084d2018-08-08 15:49:28 -0400382 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300383 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400384
Olli Etuaho44ae8992018-08-20 15:37:09 +0300385 // This initializes a simple VAO with a valid vertex buffer and index buffer with three
386 // vertices.
387 void initVAO(GLuint vao, GLuint vertexBuffer, GLuint indexBuffer)
388 {
389 glBindVertexArray(vao);
Jamie Madill04c084d2018-08-08 15:49:28 -0400390
391 const float kVertexData[3] = {0.0f};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300392 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400393 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
394
395 const unsigned int kIndices[3] = {0u, 1u, 2u};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300396 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400397 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
398 GL_STATIC_DRAW);
399 ASSERT_GL_NO_ERROR();
400 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400401};
402
Martin Radev3c25ad02017-08-22 17:36:53 +0300403class MultiviewOcclusionQueryTest : public MultiviewRenderTest
Martin Radev0d671c92017-08-10 16:41:52 +0300404{
405 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300406 MultiviewOcclusionQueryTest() {}
Martin Radev0d671c92017-08-10 16:41:52 +0300407
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400408 bool requestOcclusionQueryExtension()
409 {
410 if (extensionRequestable("GL_EXT_occlusion_query_boolean"))
411 {
412 glRequestExtensionANGLE("GL_EXT_occlusion_query_boolean");
413 }
414
415 if (!extensionEnabled("GL_EXT_occlusion_query_boolean"))
416 {
417 std::cout << "Test skipped due to missing GL_EXT_occlusion_query_boolean." << std::endl;
418 return false;
419 }
420 return true;
421 }
422
Martin Radev0d671c92017-08-10 16:41:52 +0300423 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
424 {
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400425 GLQueryEXT query;
426 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED, query);
Martin Radev0d671c92017-08-10 16:41:52 +0300427 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
428 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
429
430 GLuint result = GL_TRUE;
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400431 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT, &result);
Martin Radev0d671c92017-08-10 16:41:52 +0300432 return result;
433 }
434};
435
Olli Etuaho4bcaf992018-08-17 17:18:28 +0300436class MultiviewProgramGenerationTest : public MultiviewTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300437{
438 protected:
439 MultiviewProgramGenerationTest() {}
440};
441
Martin Radev3c25ad02017-08-22 17:36:53 +0300442class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300443{
444 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300445 MultiviewRenderPrimitiveTest() : mVBO(0u) {}
446
447 void SetUp() override
448 {
449 MultiviewRenderTest::SetUp();
450 glGenBuffers(1, &mVBO);
451 }
452
453 void TearDown() override
454 {
455 if (mVBO)
456 {
457 glDeleteBuffers(1, &mVBO);
458 mVBO = 0u;
459 }
460 MultiviewRenderTest::TearDown();
461 }
Martin Radev61bd9992017-08-11 13:10:55 +0300462
463 void setupGeometry(const std::vector<Vector2> &vertexData)
464 {
Martin Radev61bd9992017-08-11 13:10:55 +0300465 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
466 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
467 GL_STATIC_DRAW);
468 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500469 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +0300470 }
471
Martin Radev67a8a012017-09-08 13:03:52 +0300472 void checkGreenChannel(const GLubyte expectedGreenChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300473 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300474 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300475 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300476 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300477 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300478 for (int h = 0; h < mViewHeight; ++h)
479 {
480 size_t flatIndex =
481 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300482 EXPECT_EQ(GLColor(0, expectedGreenChannelData[flatIndex], 0,
483 expectedGreenChannelData[flatIndex]),
Martin Radev3c25ad02017-08-22 17:36:53 +0300484 GetViewColor(w, h, view));
485 }
Martin Radev61bd9992017-08-11 13:10:55 +0300486 }
487 }
488 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300489 GLuint mVBO;
Martin Radev61bd9992017-08-11 13:10:55 +0300490};
491
Olli Etuaho4836acc2018-08-20 15:23:18 +0300492class MultiviewSideBySideRenderTest : public MultiviewFramebufferTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300493 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev3c25ad02017-08-22 17:36:53 +0300494{
495 protected:
496 MultiviewSideBySideRenderTest()
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300497 : MultiviewFramebufferTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, 0)
Martin Radev3c25ad02017-08-22 17:36:53 +0300498 {
499 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300500
501 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
502 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
503 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
Martin Radevc1d4e552017-08-21 12:01:10 +0300504 {
505 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
506 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300507};
508
Olli Etuaho4836acc2018-08-20 15:23:18 +0300509class MultiviewLayeredRenderTest : public MultiviewFramebufferTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300510 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev72b4e1e2017-08-31 15:42:56 +0300511{
512 protected:
513 MultiviewLayeredRenderTest()
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300514 : MultiviewFramebufferTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, 0)
Martin Radev72b4e1e2017-08-31 15:42:56 +0300515 {
516 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300517 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
518 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
519 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
Martin Radevc1d4e552017-08-21 12:01:10 +0300520 {
521 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
522 }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300523};
524
Martin Radev14a26ae2017-07-24 15:56:29 +0300525// The test verifies that glDraw*Indirect:
526// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
527// than 1.
528// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +0300529TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300530{
531 if (!requestMultiviewExtension())
532 {
533 return;
534 }
535
Martin Radev14a26ae2017-07-24 15:56:29 +0300536 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +0300537
538 const std::string fsSource =
539 "#version 300 es\n"
540 "#extension GL_OVR_multiview : require\n"
541 "precision mediump float;\n"
542 "void main()\n"
543 "{}\n";
544
Olli Etuaho44ae8992018-08-20 15:37:09 +0300545 GLVertexArray vao;
546 GLBuffer vertexBuffer;
547 GLBuffer indexBuffer;
548 initVAO(vao, vertexBuffer, indexBuffer);
549
550 GLFramebuffer fbo;
551 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
552
Martin Radev14a26ae2017-07-24 15:56:29 +0300553 GLBuffer commandBuffer;
554 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
555 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
556 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
557 ASSERT_GL_NO_ERROR();
558
Olli Etuaho44ae8992018-08-20 15:37:09 +0300559 GLTexture tex2D;
560 initOnePixelColorTexture2D(tex2D);
561
Martin Radev14a26ae2017-07-24 15:56:29 +0300562 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
563 {
564 const std::string &vsSource =
565 "#version 300 es\n"
566 "#extension GL_OVR_multiview : require\n"
567 "layout(num_views = 2) in;\n"
568 "void main()\n"
569 "{}\n";
570 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
571 glUseProgram(program);
572
Olli Etuaho44ae8992018-08-20 15:37:09 +0300573 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
574 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300575
576 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
577 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
578
579 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
580 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
581 }
582
583 // Check that no errors are generated if the number of views is 1.
584 {
585 const std::string &vsSource =
586 "#version 300 es\n"
587 "#extension GL_OVR_multiview : require\n"
588 "layout(num_views = 1) in;\n"
589 "void main()\n"
590 "{}\n";
591 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
592 glUseProgram(program);
593
Olli Etuaho44ae8992018-08-20 15:37:09 +0300594 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
595 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300596
597 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
598 EXPECT_GL_NO_ERROR();
599
600 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
601 EXPECT_GL_NO_ERROR();
602 }
603}
604
Martin Radev7cf61662017-07-26 17:10:53 +0300605// The test verifies that glDraw*:
606// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
607// program differs.
608// 2) does not generate any error if the number of views is the same.
Martin Radev7cf61662017-07-26 17:10:53 +0300609TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
610{
611 if (!requestMultiviewExtension())
612 {
613 return;
614 }
615
616 const GLint viewportOffsets[4] = {0, 0, 2, 0};
617
618 const std::string &vsSource =
619 "#version 300 es\n"
620 "#extension GL_OVR_multiview : require\n"
621 "layout(num_views = 2) in;\n"
622 "void main()\n"
623 "{}\n";
624 const std::string &fsSource =
625 "#version 300 es\n"
626 "#extension GL_OVR_multiview : require\n"
627 "precision mediump float;\n"
628 "void main()\n"
629 "{}\n";
630 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
631 glUseProgram(program);
632
Olli Etuaho44ae8992018-08-20 15:37:09 +0300633 GLVertexArray vao;
634 GLBuffer vertexBuffer;
635 GLBuffer indexBuffer;
636 initVAO(vao, vertexBuffer, indexBuffer);
637
638 GLFramebuffer fbo;
639 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
640
641 GLTexture tex2D;
642 initOnePixelColorTexture2D(tex2D);
643
Martin Radev7cf61662017-07-26 17:10:53 +0300644 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
645 // number of views.
646 {
647 // The framebuffer has only 1 view.
Olli Etuaho44ae8992018-08-20 15:37:09 +0300648 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
649 1, &viewportOffsets[0]);
Martin Radev7cf61662017-07-26 17:10:53 +0300650
651 glDrawArrays(GL_TRIANGLES, 0, 3);
652 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
653
654 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
655 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
656 }
657
658 // Check that no errors are generated if the number of views in both program and draw
659 // framebuffer matches.
660 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300661 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
662 2, &viewportOffsets[0]);
Martin Radev7cf61662017-07-26 17:10:53 +0300663
664 glDrawArrays(GL_TRIANGLES, 0, 3);
665 EXPECT_GL_NO_ERROR();
666
667 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
668 EXPECT_GL_NO_ERROR();
669 }
Martin Radevda8e2572017-09-12 17:21:16 +0300670}
Martin Radev7cf61662017-07-26 17:10:53 +0300671
Martin Radevda8e2572017-09-12 17:21:16 +0300672// The test verifies that glDraw* generates an INVALID_OPERATION error if the program does not use
673// the multiview extension, but the active draw framebuffer has more than one view.
674TEST_P(MultiviewDrawValidationTest, NumViewsMismatchForNonMultiviewProgram)
675{
676 if (!requestMultiviewExtension())
Martin Radev7cf61662017-07-26 17:10:53 +0300677 {
Martin Radevda8e2572017-09-12 17:21:16 +0300678 return;
Martin Radev7cf61662017-07-26 17:10:53 +0300679 }
Martin Radevda8e2572017-09-12 17:21:16 +0300680
681 const std::string &vsSourceNoMultiview =
682 "#version 300 es\n"
683 "void main()\n"
684 "{}\n";
685 const std::string &fsSourceNoMultiview =
686 "#version 300 es\n"
687 "precision mediump float;\n"
688 "void main()\n"
689 "{}\n";
690 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
691 glUseProgram(programNoMultiview);
692
Olli Etuaho44ae8992018-08-20 15:37:09 +0300693 GLVertexArray vao;
694 GLBuffer vertexBuffer;
695 GLBuffer indexBuffer;
696 initVAO(vao, vertexBuffer, indexBuffer);
697
698 GLFramebuffer fbo;
699 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
700
701 GLTexture tex2D;
702 initOnePixelColorTexture2D(tex2D);
703
Martin Radevda8e2572017-09-12 17:21:16 +0300704 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300705 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 2,
Martin Radevda8e2572017-09-12 17:21:16 +0300706 &viewportOffsets[0]);
707
708 glDrawArrays(GL_TRIANGLES, 0, 3);
709 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
710
711 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
712 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radev7cf61662017-07-26 17:10:53 +0300713}
714
Martin Radev7e69f762017-07-27 14:54:13 +0300715// The test verifies that glDraw*:
716// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
717// greater than 1 and there is an active transform feedback object.
718// 2) does not generate any error if the number of views in the draw framebuffer is 1.
719TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
720{
721 if (!requestMultiviewExtension())
722 {
723 return;
724 }
725
726 const GLint viewportOffsets[4] = {0, 0, 2, 0};
727
728 const std::string &vsSource =
Olli Etuaho3755c482017-10-13 15:40:26 +0300729 R"(#version 300 es
730 out float tfVarying;
731 void main()
732 {
733 tfVarying = 1.0;
734 })";
Martin Radev7e69f762017-07-27 14:54:13 +0300735 const std::string &fsSource =
Olli Etuaho3755c482017-10-13 15:40:26 +0300736 R"(#version 300 es
737 precision mediump float;
738 void main()
739 {})";
Jamie Madill04c084d2018-08-08 15:49:28 -0400740
Olli Etuaho3755c482017-10-13 15:40:26 +0300741 std::vector<std::string> tfVaryings;
Jamie Madill04c084d2018-08-08 15:49:28 -0400742 tfVaryings.emplace_back("tfVarying");
743 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(singleViewProgram, vsSource, fsSource, tfVaryings,
Olli Etuaho3755c482017-10-13 15:40:26 +0300744 GL_SEPARATE_ATTRIBS);
Jamie Madill04c084d2018-08-08 15:49:28 -0400745
746 std::vector<std::string> dualViewTFVaryings;
747 dualViewTFVaryings.emplace_back("gl_Position");
748 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(dualViewProgram, kDualViewVSSource, kDualViewFSSource,
749 dualViewTFVaryings, GL_SEPARATE_ATTRIBS);
Martin Radev7e69f762017-07-27 14:54:13 +0300750
Olli Etuaho44ae8992018-08-20 15:37:09 +0300751 GLVertexArray vao;
752 GLBuffer vertexBuffer;
753 GLBuffer indexBuffer;
754 initVAO(vao, vertexBuffer, indexBuffer);
755
Martin Radev7e69f762017-07-27 14:54:13 +0300756 GLBuffer tbo;
757 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
Jamie Madill04c084d2018-08-08 15:49:28 -0400758 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 16u, nullptr, GL_STATIC_DRAW);
Martin Radev7e69f762017-07-27 14:54:13 +0300759
760 GLTransformFeedback transformFeedback;
761 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
Olli Etuaho3755c482017-10-13 15:40:26 +0300762
763 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
764
Jamie Madill04c084d2018-08-08 15:49:28 -0400765 glUseProgram(dualViewProgram);
Martin Radev7e69f762017-07-27 14:54:13 +0300766 glBeginTransformFeedback(GL_TRIANGLES);
767 ASSERT_GL_NO_ERROR();
768
Olli Etuaho44ae8992018-08-20 15:37:09 +0300769 GLFramebuffer fbo;
770 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
771
772 GLTexture tex2D;
773 initOnePixelColorTexture2D(tex2D);
774
Martin Radev7e69f762017-07-27 14:54:13 +0300775 // Check that drawArrays generates an error when there is an active transform feedback object
776 // and the number of views in the draw framebuffer is greater than 1.
777 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300778 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
779 2, &viewportOffsets[0]);
Martin Radev7e69f762017-07-27 14:54:13 +0300780 glDrawArrays(GL_TRIANGLES, 0, 3);
781 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
782 }
783
Jamie Madill04c084d2018-08-08 15:49:28 -0400784 glEndTransformFeedback();
785
786 // Ending transform feedback should allow the draw to succeed.
787 {
788 glDrawArrays(GL_TRIANGLES, 0, 3);
789 EXPECT_GL_NO_ERROR();
790 }
791
792 // A paused transform feedback should still trigger an error.
793 glBeginTransformFeedback(GL_TRIANGLES);
794 glPauseTransformFeedback();
795 ASSERT_GL_NO_ERROR();
796
797 glDrawArrays(GL_TRIANGLES, 0, 3);
798 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
799
800 // Unbind transform feedback - should succeed.
801 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
802 glDrawArrays(GL_TRIANGLES, 0, 3);
803 ASSERT_GL_NO_ERROR();
804
805 // Rebind paused transform feedback - should fail.
806 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
807 glDrawArrays(GL_TRIANGLES, 0, 3);
808 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
809
810 glResumeTransformFeedback();
811 glEndTransformFeedback();
812
813 glUseProgram(singleViewProgram);
814 glBeginTransformFeedback(GL_TRIANGLES);
815 ASSERT_GL_NO_ERROR();
816
Martin Radev7e69f762017-07-27 14:54:13 +0300817 // Check that drawArrays does not generate an error when the number of views in the draw
818 // framebuffer is 1.
819 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300820 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
821 1, &viewportOffsets[0]);
Martin Radev7e69f762017-07-27 14:54:13 +0300822 glDrawArrays(GL_TRIANGLES, 0, 3);
823 EXPECT_GL_NO_ERROR();
824 }
825
826 glEndTransformFeedback();
827}
828
Martin Radevffe754b2017-07-31 10:38:07 +0300829// The test verifies that glDraw*:
830// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
831// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
832// 2) does not generate any error if the number of views in the draw framebuffer is 1.
833TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
834{
Yunchao He9550c602018-02-13 14:47:05 +0800835 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radevffe754b2017-07-31 10:38:07 +0300836
Olli Etuaho94c91a92018-07-19 15:10:24 +0300837 if (extensionRequestable("GL_EXT_disjoint_timer_query"))
838 {
839 glRequestExtensionANGLE("GL_EXT_disjoint_timer_query");
840 }
841
Yunchao He9550c602018-02-13 14:47:05 +0800842 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_disjoint_timer_query"));
Martin Radevffe754b2017-07-31 10:38:07 +0300843
Olli Etuaho44ae8992018-08-20 15:37:09 +0300844 ANGLE_GL_PROGRAM(dualViewProgram, kDualViewVSSource, kDualViewFSSource);
845
Martin Radevffe754b2017-07-31 10:38:07 +0300846 const GLint viewportOffsets[4] = {0, 0, 2, 0};
847 const std::string &vsSource =
848 "#version 300 es\n"
849 "void main()\n"
850 "{}\n";
851 const std::string &fsSource =
852 "#version 300 es\n"
853 "precision mediump float;\n"
854 "void main()\n"
855 "{}\n";
Jamie Madill04c084d2018-08-08 15:49:28 -0400856 ANGLE_GL_PROGRAM(singleViewProgram, vsSource, fsSource);
857 glUseProgram(singleViewProgram);
Martin Radevffe754b2017-07-31 10:38:07 +0300858
Olli Etuaho44ae8992018-08-20 15:37:09 +0300859 GLVertexArray vao;
860 GLBuffer vertexBuffer;
861 GLBuffer indexBuffer;
862 initVAO(vao, vertexBuffer, indexBuffer);
863
Martin Radevffe754b2017-07-31 10:38:07 +0300864 GLuint query = 0u;
865 glGenQueriesEXT(1, &query);
866 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
867
Olli Etuaho44ae8992018-08-20 15:37:09 +0300868 GLFramebuffer fbo;
869 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
870
871 GLTexture tex2D;
872 initOnePixelColorTexture2D(tex2D);
873
Martin Radevffe754b2017-07-31 10:38:07 +0300874 // Check first case.
875 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300876 glUseProgram(dualViewProgram);
877 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
878 2, &viewportOffsets[0]);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300879 glClear(GL_COLOR_BUFFER_BIT);
880 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radevffe754b2017-07-31 10:38:07 +0300881 glDrawArrays(GL_TRIANGLES, 0, 3);
882 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
883 }
884
885 // Check second case.
886 {
Jamie Madill04c084d2018-08-08 15:49:28 -0400887 glUseProgram(singleViewProgram);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300888 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
889 1, &viewportOffsets[0]);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300890 glClear(GL_COLOR_BUFFER_BIT);
891 EXPECT_GL_NO_ERROR();
Martin Radevffe754b2017-07-31 10:38:07 +0300892 glDrawArrays(GL_TRIANGLES, 0, 3);
893 EXPECT_GL_NO_ERROR();
894 }
895
896 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
897 glDeleteQueries(1, &query);
Jamie Madill04c084d2018-08-08 15:49:28 -0400898
899 // Check starting a query after a successful draw.
900 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300901 glUseProgram(dualViewProgram);
902 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
903 2, &viewportOffsets[0]);
Jamie Madill04c084d2018-08-08 15:49:28 -0400904 glClear(GL_COLOR_BUFFER_BIT);
905 EXPECT_GL_NO_ERROR();
906 glDrawArrays(GL_TRIANGLES, 0, 3);
907 EXPECT_GL_NO_ERROR();
908
909 glGenQueriesEXT(1, &query);
910 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
911
912 glDrawArrays(GL_TRIANGLES, 0, 3);
913 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
914
915 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
916 glDrawArrays(GL_TRIANGLES, 0, 3);
917 EXPECT_GL_NO_ERROR();
918
919 glDeleteQueries(1, &query);
920 }
Martin Radevffe754b2017-07-31 10:38:07 +0300921}
922
Martin Radev8f276e22017-05-30 12:05:52 +0300923// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300924TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300925{
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300926 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +0300927 {
928 return;
929 }
930 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
931 ASSERT_GL_NO_ERROR();
932
933 checkOutput();
934}
935
936// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300937TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300938{
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300939 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +0300940 {
941 return;
942 }
943 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
944 ASSERT_GL_NO_ERROR();
945
946 checkOutput();
947}
948
949// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300950TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300951{
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300952 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +0300953 {
954 return;
955 }
956 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
957 ASSERT_GL_NO_ERROR();
958
959 checkOutput();
960}
961
962// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300963TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300964{
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300965 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +0300966 {
967 return;
968 }
969
970 const std::string vsSource =
971 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300972 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300973 "layout(num_views = 4) in;\n"
974 "in vec4 vPosition;\n"
975 "void main()\n"
976 "{\n"
977 " if (gl_ViewID_OVR == 0u) {\n"
978 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
979 " } else if (gl_ViewID_OVR == 1u) {\n"
980 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
981 " } else if (gl_ViewID_OVR == 2u) {\n"
982 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
983 " } else {\n"
984 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
985 " }"
986 " gl_Position.yzw = vPosition.yzw;\n"
987 "}\n";
988
989 const std::string fsSource =
990 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300991 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300992 "precision mediump float;\n"
993 "out vec4 col;\n"
994 "void main()\n"
995 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300996 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300997 "}\n";
998
Olli Etuaho4836acc2018-08-20 15:23:18 +0300999 updateFBOs(4, 1, 4);
Martin Radev8f276e22017-05-30 12:05:52 +03001000 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +03001001
1002 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1003 ASSERT_GL_NO_ERROR();
1004
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001005 resolveMultisampledFBO();
Martin Radev8f276e22017-05-30 12:05:52 +03001006 for (int i = 0; i < 4; ++i)
1007 {
1008 for (int j = 0; j < 4; ++j)
1009 {
Martin Radev8f276e22017-05-30 12:05:52 +03001010 if (i == j)
1011 {
Martin Radev67a8a012017-09-08 13:03:52 +03001012 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +03001013 }
1014 else
1015 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001016 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +03001017 }
1018 }
1019 }
1020 EXPECT_GL_NO_ERROR();
1021}
1022
1023// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +03001024TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +03001025{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001026 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +03001027 {
1028 return;
1029 }
1030
1031 const std::string vsSource =
1032 "#version 300 es\n"
1033 "#extension GL_OVR_multiview : require\n"
1034 "layout(num_views = 2) in;\n"
1035 "in vec4 vPosition;\n"
1036 "void main()\n"
1037 "{\n"
1038 " vec4 p = vPosition;\n"
1039 " if (gl_InstanceID == 1){\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001040 " p.y = p.y * 0.5 + 0.5;\n"
Martin Radev8f276e22017-05-30 12:05:52 +03001041 " } else {\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001042 " p.y = p.y * 0.5 - 0.5;\n"
Martin Radev8f276e22017-05-30 12:05:52 +03001043 " }\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001044 " 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 +03001045 " gl_Position.yzw = p.yzw;\n"
1046 "}\n";
1047
1048 const std::string fsSource =
1049 "#version 300 es\n"
1050 "#extension GL_OVR_multiview : require\n"
1051 "precision mediump float;\n"
1052 "out vec4 col;\n"
1053 "void main()\n"
1054 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001055 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +03001056 "}\n";
1057
Martin Radev3c25ad02017-08-22 17:36:53 +03001058 const int kViewWidth = 2;
1059 const int kViewHeight = 2;
1060 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001061 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev8f276e22017-05-30 12:05:52 +03001062 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +03001063
Martin Radev67a8a012017-09-08 13:03:52 +03001064 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 2u);
Martin Radev8f276e22017-05-30 12:05:52 +03001065 ASSERT_GL_NO_ERROR();
1066
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001067 resolveMultisampledFBO();
1068
Martin Radev67a8a012017-09-08 13:03:52 +03001069 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
1070 {{255, 0}, {255, 0}}};
Martin Radev3c25ad02017-08-22 17:36:53 +03001071
1072 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +03001073 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001074 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +03001075 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001076 for (int x = 0; x < 2; ++x)
1077 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001078 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][y][x], 0,
1079 expectedGreenChannel[view][y][x]),
Martin Radev3c25ad02017-08-22 17:36:53 +03001080 GetViewColor(x, y, view));
1081 }
Martin Radev8f276e22017-05-30 12:05:52 +03001082 }
1083 }
1084}
1085
Martin Radev553590a2017-07-31 16:40:39 +03001086// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
1087// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
1088// offset of each quad are passed as separate attributes which are indexed based on the
1089// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
1090// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
1091// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
1092// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +03001093TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +03001094{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001095 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev553590a2017-07-31 16:40:39 +03001096 {
1097 return;
1098 }
1099
Corentin Wallez02cd1522018-08-22 13:46:21 +02001100 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001101 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001102 if (IsWindows() && IsD3D11())
1103 {
1104 ignoreD3D11SDKLayersWarnings();
1105 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001106
Martin Radev553590a2017-07-31 16:40:39 +03001107 const std::string &vsSource =
1108 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001109 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001110 "layout(num_views = 2) in;\n"
1111 "in vec3 vPosition;\n"
1112 "in float offsetX;\n"
1113 "in float offsetY;\n"
1114 "void main()\n"
1115 "{\n"
1116 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001117 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001118 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
1119 " gl_Position.yzw = p.yzw;\n"
1120 "}\n";
1121
1122 const std::string &fsSource =
1123 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001124 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001125 "precision mediump float;\n"
1126 "out vec4 col;\n"
1127 "void main()\n"
1128 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001129 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001130 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +03001131
1132 const int kViewWidth = 4;
1133 const int kViewHeight = 4;
1134 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001135 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev553590a2017-07-31 16:40:39 +03001136 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev553590a2017-07-31 16:40:39 +03001137
1138 GLBuffer xOffsetVBO;
1139 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1140 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
1141 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
1142 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1143 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1144 glVertexAttribDivisor(xOffsetLoc, 3);
1145 glEnableVertexAttribArray(xOffsetLoc);
1146
1147 GLBuffer yOffsetVBO;
1148 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1149 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1150 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1151 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1152 glVertexAttribDivisor(yOffsetLoc, 1);
1153 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1154 glEnableVertexAttribArray(yOffsetLoc);
1155
Martin Radev67a8a012017-09-08 13:03:52 +03001156 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev553590a2017-07-31 16:40:39 +03001157 ASSERT_GL_NO_ERROR();
1158
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001159 resolveMultisampledFBO();
1160
Martin Radev67a8a012017-09-08 13:03:52 +03001161 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001162 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1163 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1164 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +03001165 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001166 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +03001167 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001168 for (int col = 0; col < 4; ++col)
1169 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001170 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0,
1171 expectedGreenChannel[view][row][col]),
Martin Radev3c25ad02017-08-22 17:36:53 +03001172 GetViewColor(col, row, view));
1173 }
Martin Radev553590a2017-07-31 16:40:39 +03001174 }
1175 }
1176}
1177
1178// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1179// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +03001180TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +03001181{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001182 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev553590a2017-07-31 16:40:39 +03001183 {
1184 return;
1185 }
1186
Olli Etuaho4836acc2018-08-20 15:23:18 +03001187 updateFBOs(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +03001188
1189 // Create multiview program.
1190 const std::string &vs =
1191 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001192 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001193 "layout(num_views = 2) in;\n"
1194 "layout(location = 0) in vec2 vPosition;\n"
1195 "layout(location = 1) in float offsetX;\n"
1196 "void main()\n"
1197 "{\n"
1198 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1199 " p.x += offsetX;\n"
1200 " gl_Position = p;\n"
1201 "}\n";
1202
1203 const std::string &fs =
1204 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001205 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001206 "precision mediump float;\n"
1207 "out vec4 col;\n"
1208 "void main()\n"
1209 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001210 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001211 "}\n";
1212
1213 ANGLE_GL_PROGRAM(program, vs, fs);
1214
1215 const std::string &dummyVS =
1216 "#version 300 es\n"
1217 "layout(location = 0) in vec2 vPosition;\n"
1218 "layout(location = 1) in float offsetX;\n"
1219 "void main()\n"
1220 "{\n"
1221 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1222 "}\n";
1223
1224 const std::string &dummyFS =
1225 "#version 300 es\n"
1226 "precision mediump float;\n"
1227 "out vec4 col;\n"
1228 "void main()\n"
1229 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001230 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001231 "}\n";
1232
1233 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
1234
1235 GLBuffer xOffsetVBO;
1236 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1237 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1238 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1239 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1240
1241 GLBuffer vertexVBO;
1242 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1243 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1244 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1245 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1246
1247 GLVertexArray vao[2];
1248 for (size_t i = 0u; i < 2u; ++i)
1249 {
1250 glBindVertexArray(vao[i]);
1251
1252 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1253 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1254 glEnableVertexAttribArray(0);
1255
1256 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1257 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1258 glEnableVertexAttribArray(1);
1259 }
1260 ASSERT_GL_NO_ERROR();
1261
1262 glViewport(0, 0, 1, 1);
1263 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001264 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001265 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001266
1267 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1268 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1269 // bits are cleared.
1270 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001271 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1272 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001273 glBindVertexArray(vao[0]);
1274 glVertexAttribDivisor(1, 0);
1275 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1276 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001277 ASSERT_GL_NO_ERROR();
1278
1279 // Check that vertexAttribDivisor uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001280 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001281 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001282 glUseProgram(program);
1283 glVertexAttribDivisor(1, 1);
1284 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001285
1286 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001287 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1288 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001289
1290 // Clear the buffers and propagate divisor to the driver.
1291 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1292 // dirty bits when useProgram is called.
1293 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001294 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1295 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001296 glVertexAttribDivisor(1, 1);
1297 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1298 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001299 ASSERT_GL_NO_ERROR();
1300
1301 // Check that useProgram uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001302 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001303 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001304 glUseProgram(program);
1305 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001306
1307 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001308 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1309 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001310
1311 // We go through similar steps as before.
1312 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001313 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1314 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001315 glVertexAttribDivisor(1, 1);
1316 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1317 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001318 ASSERT_GL_NO_ERROR();
1319
1320 // Check that bindVertexArray uses the number of views to update the divisor.
1321 {
1322 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1323 // divisor for vao[1] only.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001324 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001325 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001326 glBindVertexArray(vao[1]);
1327 glUseProgram(program);
1328 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001329 glBindVertexArray(0);
1330 ASSERT_GL_NO_ERROR();
1331 }
1332 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1333 // adjusts the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001334 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001335 glBindVertexArray(vao[0]);
1336 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001337
1338 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001339 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1340 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001341}
1342
Martin Radev0d671c92017-08-10 16:41:52 +03001343// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1344// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001345TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001346{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001347 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1348 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001349
1350 const std::string vsSource =
1351 "#version 300 es\n"
1352 "#extension GL_OVR_multiview : require\n"
1353 "layout(num_views = 2) in;\n"
1354 "in vec3 vPosition;\n"
1355 "void main()\n"
1356 "{\n"
1357 " gl_Position.x = 2.0;\n"
1358 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1359 "}\n";
1360
1361 const std::string fsSource =
1362 "#version 300 es\n"
1363 "#extension GL_OVR_multiview : require\n"
1364 "precision mediump float;\n"
1365 "out vec4 col;\n"
1366 "void main()\n"
1367 "{\n"
1368 " col = vec4(1,0,0,0);\n"
1369 "}\n";
1370 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001371 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001372
1373 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1374 ASSERT_GL_NO_ERROR();
1375 EXPECT_GL_FALSE(result);
1376}
1377
1378// Test that there are fragments passing the occlusion query if only view 0 can produce
1379// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001380TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001381{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001382 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1383 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001384
1385 const std::string vsSource =
1386 "#version 300 es\n"
1387 "#extension GL_OVR_multiview : require\n"
1388 "layout(num_views = 2) in;\n"
1389 "in vec3 vPosition;\n"
1390 "void main()\n"
1391 "{\n"
1392 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1393 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1394 "}\n";
1395
1396 const std::string fsSource =
1397 "#version 300 es\n"
1398 "#extension GL_OVR_multiview : require\n"
1399 "precision mediump float;\n"
1400 "out vec4 col;\n"
1401 "void main()\n"
1402 "{\n"
1403 " col = vec4(1,0,0,0);\n"
1404 "}\n";
1405 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001406 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001407
1408 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1409 ASSERT_GL_NO_ERROR();
1410 EXPECT_GL_TRUE(result);
1411}
1412
1413// Test that there are fragments passing the occlusion query if only view 1 can produce
1414// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001415TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001416{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001417 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1418 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001419
1420 const std::string vsSource =
1421 "#version 300 es\n"
1422 "#extension GL_OVR_multiview : require\n"
1423 "layout(num_views = 2) in;\n"
1424 "in vec3 vPosition;\n"
1425 "void main()\n"
1426 "{\n"
1427 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1428 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1429 "}\n";
1430
1431 const std::string fsSource =
1432 "#version 300 es\n"
1433 "#extension GL_OVR_multiview : require\n"
1434 "precision mediump float;\n"
1435 "out vec4 col;\n"
1436 "void main()\n"
1437 "{\n"
1438 " col = vec4(1,0,0,0);\n"
1439 "}\n";
1440 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001441 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001442
1443 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1444 ASSERT_GL_NO_ERROR();
1445 EXPECT_GL_TRUE(result);
1446}
1447
Martin Radev41ac68e2017-06-06 12:16:58 +03001448// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1449// compiles and links without an error.
1450TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1451{
1452 if (!requestMultiviewExtension())
1453 {
1454 return;
1455 }
1456
1457 const std::string vsSource =
1458 "#version 300 es\n"
1459 "#extension GL_OVR_multiview : require\n"
1460 "layout(num_views = 2) in;\n"
1461 "void main()\n"
1462 "{\n"
1463 "}\n";
1464
1465 const std::string fsSource =
1466 "#version 300 es\n"
1467 "#extension GL_OVR_multiview : require\n"
1468 "precision mediump float;\n"
1469 "void main()\n"
1470 "{\n"
1471 "}\n";
1472
1473 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1474 glUseProgram(program);
1475
1476 EXPECT_GL_NO_ERROR();
1477}
1478
1479// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1480// without an error.
1481TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1482{
1483 if (!requestMultiviewExtension())
1484 {
1485 return;
1486 }
1487
1488 const std::string vsSource =
1489 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001490 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001491 "layout(num_views = 2) in;\n"
1492 "void main()\n"
1493 "{\n"
1494 " if (gl_ViewID_OVR == 0u) {\n"
1495 " gl_Position = vec4(1,0,0,1);\n"
1496 " } else {\n"
1497 " gl_Position = vec4(-1,0,0,1);\n"
1498 " }\n"
1499 "}\n";
1500
1501 const std::string fsSource =
1502 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001503 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001504 "precision mediump float;\n"
1505 "void main()\n"
1506 "{\n"
1507 "}\n";
1508
1509 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1510 glUseProgram(program);
1511
1512 EXPECT_GL_NO_ERROR();
1513}
1514
1515// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1516// without an error.
1517TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1518{
1519 if (!requestMultiviewExtension())
1520 {
1521 return;
1522 }
1523
1524 const std::string vsSource =
1525 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001526 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001527 "layout(num_views = 2) in;\n"
1528 "void main()\n"
1529 "{\n"
1530 "}\n";
1531
1532 const std::string fsSource =
1533 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001534 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001535 "precision mediump float;\n"
1536 "out vec4 col;\n"
1537 "void main()\n"
1538 "{\n"
1539 " if (gl_ViewID_OVR == 0u) {\n"
1540 " col = vec4(1,0,0,1);\n"
1541 " } else {\n"
1542 " col = vec4(-1,0,0,1);\n"
1543 " }\n"
1544 "}\n";
1545
1546 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1547 glUseProgram(program);
1548
1549 EXPECT_GL_NO_ERROR();
1550}
1551
Martin Radev61bd9992017-08-11 13:10:55 +03001552// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001553TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001554{
1555 if (!requestMultiviewExtension())
1556 {
1557 return;
1558 }
1559
Geoff Lang25858162017-11-06 11:25:58 -05001560 // Test failing on P400 graphics card (anglebug.com/2228)
1561 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1562
Martin Radev61bd9992017-08-11 13:10:55 +03001563 const std::string vsSource =
1564 "#version 300 es\n"
1565 "#extension GL_OVR_multiview : require\n"
1566 "layout(num_views = 2) in;\n"
1567 "layout(location=0) in vec2 vPosition;\n"
1568 "void main()\n"
1569 "{\n"
1570 " gl_PointSize = 1.0;\n"
1571 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1572 "}\n";
1573
1574 const std::string fsSource =
1575 "#version 300 es\n"
1576 "#extension GL_OVR_multiview : require\n"
1577 "precision mediump float;\n"
1578 "out vec4 col;\n"
1579 "void main()\n"
1580 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001581 " col = vec4(0,1,0,1);\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001582 "}\n";
1583 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1584 glUseProgram(program);
1585
Martin Radev3c25ad02017-08-22 17:36:53 +03001586 const int kViewWidth = 4;
1587 const int kViewHeight = 2;
1588 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001589 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001590
1591 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1592 std::vector<Vector2> vertexDataInClipSpace =
1593 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1594 setupGeometry(vertexDataInClipSpace);
1595
1596 glDrawArrays(GL_POINTS, 0, 2);
1597
Martin Radev67a8a012017-09-08 13:03:52 +03001598 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001599 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001600 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001601}
1602
1603// The test checks that GL_LINES is correctly rendered.
1604// The behavior of this test is not guaranteed by the spec:
1605// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1606// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1607// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1608// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001609TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001610{
1611 if (!requestMultiviewExtension())
1612 {
1613 return;
1614 }
1615
Martin Radevced5c862017-08-17 16:05:29 +03001616 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001617 ASSERT_NE(program, 0u);
1618 glUseProgram(program);
1619 ASSERT_GL_NO_ERROR();
1620
Martin Radev3c25ad02017-08-22 17:36:53 +03001621 const int kViewWidth = 4;
1622 const int kViewHeight = 2;
1623 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001624 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001625
1626 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1627 std::vector<Vector2> vertexDataInClipSpace =
1628 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1629 setupGeometry(vertexDataInClipSpace);
1630
1631 glDrawArrays(GL_LINES, 0, 2);
1632
Martin Radev67a8a012017-09-08 13:03:52 +03001633 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001634 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001635 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001636
1637 glDeleteProgram(program);
1638}
1639
1640// The test checks that GL_LINE_STRIP is correctly rendered.
1641// The behavior of this test is not guaranteed by the spec:
1642// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1643// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1644// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1645// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001646TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001647{
1648 if (!requestMultiviewExtension())
1649 {
1650 return;
1651 }
1652
Martin Radevced5c862017-08-17 16:05:29 +03001653 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001654 ASSERT_NE(program, 0u);
1655 glUseProgram(program);
1656 ASSERT_GL_NO_ERROR();
1657
Martin Radev3c25ad02017-08-22 17:36:53 +03001658 const int kViewWidth = 4;
1659 const int kViewHeight = 2;
1660 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001661 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001662
1663 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1664 std::vector<Vector2> vertexDataInClipSpace =
1665 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1666 setupGeometry(vertexDataInClipSpace);
1667
1668 glDrawArrays(GL_LINE_STRIP, 0, 3);
1669
Martin Radev67a8a012017-09-08 13:03:52 +03001670 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001671 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001672 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001673
1674 glDeleteProgram(program);
1675}
1676
1677// The test checks that GL_LINE_LOOP is correctly rendered.
1678// The behavior of this test is not guaranteed by the spec:
1679// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1680// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1681// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1682// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001683TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001684{
1685 if (!requestMultiviewExtension())
1686 {
1687 return;
1688 }
1689
Martin Radevced5c862017-08-17 16:05:29 +03001690 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001691 ASSERT_NE(program, 0u);
1692 glUseProgram(program);
1693 ASSERT_GL_NO_ERROR();
1694
Martin Radev3c25ad02017-08-22 17:36:53 +03001695 const int kViewWidth = 4;
1696 const int kViewHeight = 4;
1697 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001698 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001699
1700 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1701 Vector2I(0, 3)};
1702 std::vector<Vector2> vertexDataInClipSpace =
1703 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1704 setupGeometry(vertexDataInClipSpace);
1705
1706 glDrawArrays(GL_LINE_LOOP, 0, 4);
1707
Martin Radev67a8a012017-09-08 13:03:52 +03001708 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001709 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1710 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001711 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001712
1713 glDeleteProgram(program);
1714}
1715
1716// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001717TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001718{
1719 if (!requestMultiviewExtension())
1720 {
1721 return;
1722 }
1723
Martin Radevced5c862017-08-17 16:05:29 +03001724 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001725 ASSERT_NE(program, 0u);
1726 glUseProgram(program);
1727 ASSERT_GL_NO_ERROR();
1728
1729 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1730 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1731 setupGeometry(vertexDataInClipSpace);
1732
Martin Radev3c25ad02017-08-22 17:36:53 +03001733 const int kViewWidth = 2;
1734 const int kViewHeight = 2;
1735 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001736 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001737
1738 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1739
Martin Radev67a8a012017-09-08 13:03:52 +03001740 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1741 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1742 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001743
1744 glDeleteProgram(program);
1745}
1746
1747// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001748TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001749{
1750 if (!requestMultiviewExtension())
1751 {
1752 return;
1753 }
1754
Martin Radevced5c862017-08-17 16:05:29 +03001755 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001756 ASSERT_NE(program, 0u);
1757 glUseProgram(program);
1758 ASSERT_GL_NO_ERROR();
1759
1760 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1761 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1762 setupGeometry(vertexDataInClipSpace);
1763
Martin Radev3c25ad02017-08-22 17:36:53 +03001764 const int kViewWidth = 2;
1765 const int kViewHeight = 2;
1766 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001767 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001768
1769 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1770
Martin Radev67a8a012017-09-08 13:03:52 +03001771 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1772 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1773 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001774
1775 glDeleteProgram(program);
1776}
1777
1778// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1779// bounds. The test does not rely on the actual line width being greater than 1.0.
Martin Radev3c25ad02017-08-22 17:36:53 +03001780TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
Martin Radev61bd9992017-08-11 13:10:55 +03001781{
1782 if (!requestMultiviewExtension())
1783 {
1784 return;
1785 }
1786
Olli Etuaho9259fd02018-08-22 12:12:00 +03001787 GLTexture colorTexture;
Martin Radev61bd9992017-08-11 13:10:55 +03001788
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001789 CreateMultiviewBackingTextures(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, 0, 2, 1, 2,
Olli Etuaho9259fd02018-08-22 12:12:00 +03001790 colorTexture, 0u, 0u);
1791
1792 GLFramebuffer drawFramebuffer;
1793 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFramebuffer);
Martin Radev61bd9992017-08-11 13:10:55 +03001794 GLint viewportOffsets[4] = {1, 0, 3, 0};
1795 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
Olli Etuaho9259fd02018-08-22 12:12:00 +03001796 colorTexture, 0, 2, &viewportOffsets[0]);
1797
1798 GLFramebuffer readFramebuffer;
1799 glBindFramebuffer(GL_READ_FRAMEBUFFER, readFramebuffer);
1800 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture,
1801 0);
1802
1803 ASSERT_GL_NO_ERROR();
Martin Radev61bd9992017-08-11 13:10:55 +03001804
1805 glViewport(0, 0, 1, 1);
1806 glScissor(0, 0, 1, 1);
1807 glEnable(GL_SCISSOR_TEST);
1808
1809 const std::string vsSource =
1810 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001811 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001812 "layout(num_views = 2) in;\n"
1813 "layout(location=0) in vec2 vPosition;\n"
1814 "void main()\n"
1815 "{\n"
1816 " gl_PointSize = 10.0;\n"
1817 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1818 "}\n";
1819
1820 const std::string fsSource =
1821 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001822 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001823 "precision mediump float;\n"
1824 "out vec4 col;\n"
1825 "void main()\n"
1826 "{\n"
1827 " if (gl_ViewID_OVR == 0u) {\n"
1828 " col = vec4(1,0,0,1);\n"
1829 " } else {\n"
1830 " col = vec4(0,1,0,1);\n"
1831 " }\n"
1832 "}\n";
1833 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1834 glUseProgram(program);
1835
1836 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1837 const std::vector<Vector2> &vertexDataInClipSpace =
1838 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001839
1840 GLBuffer vbo;
1841 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1842 glBufferData(GL_ARRAY_BUFFER, vertexDataInClipSpace.size() * sizeof(Vector2),
1843 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1844 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -05001845 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +03001846
1847 // Test rendering points.
1848 {
1849 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1850 glDrawArrays(GL_POINTS, 0, 2);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001851 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001852 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001853 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001854 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1855 }
1856
1857 // Test rendering lines.
1858 {
1859 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1860 glLineWidth(10.f);
1861 glDrawArrays(GL_LINES, 0, 2);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001862 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001863 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001864 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001865 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1866 }
1867}
1868
Martin Radev0abb7a22017-08-28 15:34:45 +03001869// Verify that re-linking a program adjusts the attribute divisor.
1870// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1871// to each other. The quads' position and color depend on the corresponding attribute divisors.
1872TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1873{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001874 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev0abb7a22017-08-28 15:34:45 +03001875 {
1876 return;
1877 }
1878
Corentin Wallez02cd1522018-08-22 13:46:21 +02001879 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001880 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001881 if (IsWindows() && IsD3D11())
1882 {
1883 ignoreD3D11SDKLayersWarnings();
1884 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001885
Martin Radev0abb7a22017-08-28 15:34:45 +03001886 const int kViewWidth = 4;
1887 const int kViewHeight = 1;
1888 const int kNumViews = 2;
1889
1890 const std::string &fsSource =
1891 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001892 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001893 "precision mediump float;\n"
1894 "in vec4 oColor;\n"
1895 "out vec4 col;\n"
1896 "void main()\n"
1897 "{\n"
1898 " col = oColor;\n"
1899 "}\n";
1900
1901 auto generateVertexShaderSource = [](int numViews) -> std::string {
1902 std::string source =
1903 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001904 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001905 "layout(num_views = " +
1906 ToString(numViews) +
1907 ") in;\n"
1908 "in vec3 vPosition;\n"
1909 "in float vOffsetX;\n"
1910 "in vec4 vColor;\n"
1911 "out vec4 oColor;\n"
1912 "void main()\n"
1913 "{\n"
1914 " vec4 p = vec4(vPosition, 1.);\n"
1915 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1916 " oColor = vColor;\n"
1917 " gl_Position = p;\n"
1918 "}\n";
1919 return source;
1920 };
1921
1922 std::string vsSource = generateVertexShaderSource(kNumViews);
1923 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1924 glUseProgram(program);
1925
1926 GLint positionLoc;
1927 GLBuffer xOffsetVBO;
1928 GLint xOffsetLoc;
1929 GLBuffer colorVBO;
1930 GLint colorLoc;
1931
1932 {
1933 // Initialize buffers and setup attributes.
1934 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1935 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1936 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1937 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1938 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1939 glVertexAttribDivisor(xOffsetLoc, 1);
1940 glEnableVertexAttribArray(xOffsetLoc);
1941
1942 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1943 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1944 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1945 colorLoc = glGetAttribLocation(program, "vColor");
1946 glVertexAttribDivisor(colorLoc, 2);
1947 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1948 glEnableVertexAttribArray(colorLoc);
1949
1950 positionLoc = glGetAttribLocation(program, "vPosition");
1951 }
1952
1953 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001954 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001955
Martin Radev67a8a012017-09-08 13:03:52 +03001956 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001957 ASSERT_GL_NO_ERROR();
1958
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001959 resolveMultisampledFBO();
Martin Radev0abb7a22017-08-28 15:34:45 +03001960 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1961 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1962 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1963 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1964 }
1965
1966 {
1967 const int kNewNumViews = 3;
1968 vsSource = generateVertexShaderSource(kNewNumViews);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001969 updateFBOs(kViewWidth, kViewHeight, kNewNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001970
1971 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
1972 ASSERT_NE(0u, vs);
1973 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
1974 ASSERT_NE(0u, fs);
1975
1976 GLint numAttachedShaders = 0;
1977 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1978
1979 GLuint attachedShaders[2] = {0u};
1980 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1981 for (int i = 0; i < 2; ++i)
1982 {
1983 glDetachShader(program, attachedShaders[i]);
1984 }
1985
1986 glAttachShader(program, vs);
1987 glDeleteShader(vs);
1988
1989 glAttachShader(program, fs);
1990 glDeleteShader(fs);
1991
1992 glBindAttribLocation(program, positionLoc, "vPosition");
1993 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1994 glBindAttribLocation(program, colorLoc, "vColor");
1995
1996 glLinkProgram(program);
1997
Martin Radev67a8a012017-09-08 13:03:52 +03001998 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001999 ASSERT_GL_NO_ERROR();
2000
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002001 resolveMultisampledFBO();
Martin Radev0abb7a22017-08-28 15:34:45 +03002002 for (int i = 0; i < kNewNumViews; ++i)
2003 {
2004 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
2005 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
2006 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
2007 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
2008 }
2009 }
2010}
2011
Martin Radevced5c862017-08-17 16:05:29 +03002012// Test that useProgram applies the number of views in computing the final value of the attribute
2013// divisor.
2014TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
2015{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002016 if (!requestMultiviewExtension(isMultisampled()))
Martin Radevced5c862017-08-17 16:05:29 +03002017 {
2018 return;
2019 }
2020
Geoff Lang25858162017-11-06 11:25:58 -05002021 // Test failing on P400 graphics card (anglebug.com/2228)
2022 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
2023
Olli Etuaho44ae8992018-08-20 15:37:09 +03002024 // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
2025 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03002026 if (IsWindows() && IsD3D11())
2027 {
2028 ignoreD3D11SDKLayersWarnings();
2029 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03002030
Martin Radevced5c862017-08-17 16:05:29 +03002031 GLVertexArray vao;
2032 glBindVertexArray(vao);
2033 GLBuffer vbo;
2034 glBindBuffer(GL_ARRAY_BUFFER, vbo);
2035 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
2036 Vector2I(3, 0)};
2037 std::vector<Vector2> vertexDataInClipSpace =
2038 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
2039 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
2040 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
2041 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
2042 glEnableVertexAttribArray(0);
2043 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
2044 glVertexAttribDivisor(0, 1);
2045 ASSERT_GL_NO_ERROR();
2046
2047 // Create a program and fbo with N views and draw N instances of a point horizontally.
2048 for (int numViews = 2; numViews <= 4; ++numViews)
2049 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03002050 updateFBOs(4, 1, numViews);
Martin Radevced5c862017-08-17 16:05:29 +03002051 ASSERT_GL_NO_ERROR();
2052
2053 GLuint program = CreateSimplePassthroughProgram(numViews);
2054 ASSERT_NE(program, 0u);
2055 glUseProgram(program);
2056 ASSERT_GL_NO_ERROR();
2057
2058 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
2059
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002060 resolveMultisampledFBO();
Martin Radevced5c862017-08-17 16:05:29 +03002061 for (int view = 0; view < numViews; ++view)
2062 {
2063 for (int j = 0; j < numViews; ++j)
2064 {
Martin Radev67a8a012017-09-08 13:03:52 +03002065 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03002066 }
2067 for (int j = numViews; j < 4; ++j)
2068 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03002069 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03002070 }
2071 }
2072
2073 glDeleteProgram(program);
2074 }
2075}
2076
Martin Radev72b4e1e2017-08-31 15:42:56 +03002077// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
2078TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
2079{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002080 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev72b4e1e2017-08-31 15:42:56 +03002081 {
2082 return;
2083 }
2084
2085 const std::string vsSource =
2086 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002087 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002088 "layout(num_views = 3) in;\n"
2089 "in vec3 vPosition;\n"
2090 "void main()\n"
2091 "{\n"
2092 " gl_Position = vec4(vPosition, 1.);\n"
2093 "}\n";
2094
2095 const std::string fsSource =
2096 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002097 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002098 "precision mediump float;\n"
2099 "out vec4 col;\n"
2100 "void main()\n"
2101 "{\n"
2102 " if (gl_ViewID_OVR == 0u) {\n"
2103 " col = vec4(1,0,0,1);\n"
2104 " } else if (gl_ViewID_OVR == 1u) {\n"
2105 " col = vec4(0,1,0,1);\n"
2106 " } else if (gl_ViewID_OVR == 2u) {\n"
2107 " col = vec4(0,0,1,1);\n"
2108 " } else {\n"
2109 " col = vec4(0,0,0,0);\n"
2110 " }\n"
2111 "}\n";
2112
Olli Etuaho4836acc2018-08-20 15:23:18 +03002113 updateFBOs(1, 1, 3);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002114 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002115
2116 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2117 ASSERT_GL_NO_ERROR();
2118
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002119 resolveMultisampledFBO();
Martin Radev72b4e1e2017-08-31 15:42:56 +03002120 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2121 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2122 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
2123}
2124
2125// The test checks that the inactive layers of a 2D texture array are not written to by a
2126// multi-view program.
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002127TEST_P(MultiviewLayeredRenderTest, RenderToSubrangeOfLayers)
Martin Radev72b4e1e2017-08-31 15:42:56 +03002128{
2129 if (!requestMultiviewExtension())
2130 {
2131 return;
2132 }
2133
2134 const std::string vsSource =
2135 "#version 300 es\n"
2136 "#extension GL_OVR_multiview : require\n"
2137 "layout(num_views = 2) in;\n"
2138 "in vec3 vPosition;\n"
2139 "void main()\n"
2140 "{\n"
2141 " gl_Position = vec4(vPosition, 1.);\n"
2142 "}\n";
2143
2144 const std::string fsSource =
2145 "#version 300 es\n"
2146 "#extension GL_OVR_multiview : require\n"
2147 "precision mediump float;\n"
2148 "out vec4 col;\n"
2149 "void main()\n"
2150 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002151 " col = vec4(0,1,0,1);\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002152 "}\n";
2153
Olli Etuaho4836acc2018-08-20 15:23:18 +03002154 updateFBOs(1, 1, 2, 4, 1);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002155 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002156
2157 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2158 ASSERT_GL_NO_ERROR();
2159
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002160 resolveMultisampledFBO();
Martin Radev72b4e1e2017-08-31 15:42:56 +03002161 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +03002162 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2163 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002164 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
2165}
2166
Martin Radevc1d4e552017-08-21 12:01:10 +03002167// The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
2168// potential bugs if the view is selected in the VS. The test contains a program in which the
2169// gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
2170// fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
2171// never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
2172// green for view 1.
2173TEST_P(MultiviewRenderTest, FlatInterpolation)
Martin Radev3c25ad02017-08-22 17:36:53 +03002174{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002175 if (!requestMultiviewExtension(isMultisampled()))
Martin Radevc1d4e552017-08-21 12:01:10 +03002176 {
2177 return;
2178 }
2179
2180 const std::string vsSource =
2181 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002182 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002183 "layout(num_views = 2) in;\n"
2184 "in vec3 vPosition;\n"
2185 "flat out int oInstanceID;\n"
2186 "void main()\n"
2187 "{\n"
2188 " gl_Position = vec4(vPosition, 1.);\n"
2189 " oInstanceID = gl_InstanceID;\n"
2190 "}\n";
2191
2192 const std::string fsSource =
2193 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002194 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002195 "precision mediump float;\n"
2196 "flat in int oInstanceID;\n"
2197 "out vec4 col;\n"
2198 "void main()\n"
2199 "{\n"
2200 " if (oInstanceID < 0) {\n"
2201 " discard;\n"
2202 " }\n"
2203 " if (gl_ViewID_OVR == 0u) {\n"
2204 " col = vec4(1,0,0,1);\n"
2205 " } else {\n"
2206 " col = vec4(0,1,0,1);\n"
2207 " }\n"
2208 "}\n";
2209
Olli Etuaho4836acc2018-08-20 15:23:18 +03002210 updateFBOs(1, 1, 2);
Martin Radevc1d4e552017-08-21 12:01:10 +03002211 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2212
2213 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2214 ASSERT_GL_NO_ERROR();
2215
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002216 resolveMultisampledFBO();
Martin Radevc1d4e552017-08-21 12:01:10 +03002217 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2218 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +03002219}
2220
Olli Etuaho604d8732018-07-20 11:02:43 +03002221// This test assigns gl_ViewID_OVR to a flat int varying and then sets the color based on that
2222// varying in the fragment shader.
2223TEST_P(MultiviewRenderTest, FlatInterpolation2)
2224{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002225 if (!requestMultiviewExtension(isMultisampled()))
Olli Etuaho604d8732018-07-20 11:02:43 +03002226 {
2227 return;
2228 }
2229
2230 const std::string vsSource =
2231 "#version 300 es\n"
2232 "#extension GL_OVR_multiview : require\n"
2233 "layout(num_views = 2) in;\n"
2234 "in vec3 vPosition;\n"
2235 "flat out int flatVarying;\n"
2236 "void main()\n"
2237 "{\n"
2238 " gl_Position = vec4(vPosition, 1.);\n"
2239 " flatVarying = int(gl_ViewID_OVR);\n"
2240 "}\n";
2241
2242 const std::string fsSource =
2243 "#version 300 es\n"
2244 "#extension GL_OVR_multiview : require\n"
2245 "precision mediump float;\n"
2246 "flat in int flatVarying;\n"
2247 "out vec4 col;\n"
2248 "void main()\n"
2249 "{\n"
2250 " if (flatVarying == 0) {\n"
2251 " col = vec4(1,0,0,1);\n"
2252 " } else {\n"
2253 " col = vec4(0,1,0,1);\n"
2254 " }\n"
2255 "}\n";
2256
Olli Etuaho4836acc2018-08-20 15:23:18 +03002257 updateFBOs(1, 1, 2);
Olli Etuaho604d8732018-07-20 11:02:43 +03002258 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2259
2260 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2261 ASSERT_GL_NO_ERROR();
2262
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002263 resolveMultisampledFBO();
Olli Etuaho604d8732018-07-20 11:02:43 +03002264 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2265 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2266}
2267
Martin Radev265a6d42017-09-12 16:51:37 +03002268// The test is added to cover a bug which resulted in the viewport/scissor and viewport offsets not
2269// being correctly applied.
2270TEST_P(MultiviewSideBySideRenderTest, ViewportOffsetsAppliedBugCoverage)
2271{
2272 if (!requestMultiviewExtension())
2273 {
2274 return;
2275 }
2276
Olli Etuaho4836acc2018-08-20 15:23:18 +03002277 updateFBOs(1, 1, 2);
Martin Radev265a6d42017-09-12 16:51:37 +03002278
2279 // Create multiview program.
2280 const std::string &vs =
2281 "#version 300 es\n"
2282 "#extension GL_OVR_multiview : require\n"
2283 "layout(num_views = 2) in;\n"
2284 "layout(location = 0) in vec3 vPosition;\n"
2285 "void main()\n"
2286 "{\n"
2287 " gl_Position = vec4(vPosition, 1.0);\n"
2288 "}\n";
2289
2290 const std::string &fs =
2291 "#version 300 es\n"
2292 "#extension GL_OVR_multiview : require\n"
2293 "precision mediump float;\n"
2294 "out vec4 col;\n"
2295 "void main()\n"
2296 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002297 " col = vec4(0,1,0,1);\n"
Martin Radev265a6d42017-09-12 16:51:37 +03002298 "}\n";
2299
2300 ANGLE_GL_PROGRAM(program, vs, fs);
2301
2302 glViewport(0, 0, 1, 1);
2303 glScissor(0, 0, 1, 1);
2304 glEnable(GL_SCISSOR_TEST);
2305 glClearColor(0, 0, 0, 1);
2306
2307 // Bind the default FBO and make sure that the state is synchronized.
2308 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
2309 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2310 ASSERT_GL_NO_ERROR();
2311
2312 // Draw and check that both views are rendered to.
Olli Etuaho4836acc2018-08-20 15:23:18 +03002313 bindMemberDrawFramebuffer();
Martin Radev265a6d42017-09-12 16:51:37 +03002314 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev67a8a012017-09-08 13:03:52 +03002315
Martin Radev265a6d42017-09-12 16:51:37 +03002316 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
Martin Radev67a8a012017-09-08 13:03:52 +03002317 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
2318 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev265a6d42017-09-12 16:51:37 +03002319}
2320
Olli Etuahof26b27e2018-08-17 11:01:19 +03002321MultiviewRenderTestParams SideBySideVertexShaderOpenGL(GLint majorVersion = 3,
2322 GLint minorVersion = 0)
Martin Radev3c25ad02017-08-22 17:36:53 +03002323{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002324 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, 0,
Olli Etuahof26b27e2018-08-17 11:01:19 +03002325 VertexShaderOpenGL(majorVersion, minorVersion));
Martin Radev3c25ad02017-08-22 17:36:53 +03002326}
2327
Olli Etuahof26b27e2018-08-17 11:01:19 +03002328MultiviewRenderTestParams LayeredVertexShaderOpenGL()
Martin Radev3c25ad02017-08-22 17:36:53 +03002329{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002330 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, 0,
Olli Etuahof26b27e2018-08-17 11:01:19 +03002331 VertexShaderOpenGL(3, 0));
Martin Radev3c25ad02017-08-22 17:36:53 +03002332}
2333
Olli Etuahof26b27e2018-08-17 11:01:19 +03002334MultiviewRenderTestParams SideBySideGeomShaderD3D11()
Martin Radev72b4e1e2017-08-31 15:42:56 +03002335{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002336 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, 0,
Olli Etuahof26b27e2018-08-17 11:01:19 +03002337 GeomShaderD3D11(3, 0));
Martin Radevc1d4e552017-08-21 12:01:10 +03002338}
2339
Olli Etuahof26b27e2018-08-17 11:01:19 +03002340MultiviewRenderTestParams LayeredGeomShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002341{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002342 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, 0,
2343 GeomShaderD3D11(3, 0));
Martin Radevc1d4e552017-08-21 12:01:10 +03002344}
2345
Olli Etuahof26b27e2018-08-17 11:01:19 +03002346MultiviewRenderTestParams SideBySideVertexShaderD3D11(GLint majorVersion = 3,
2347 GLint minorVersion = 0)
Martin Radevc1d4e552017-08-21 12:01:10 +03002348{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002349 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, 0,
Olli Etuahof26b27e2018-08-17 11:01:19 +03002350 VertexShaderD3D11(majorVersion, minorVersion));
Martin Radevc1d4e552017-08-21 12:01:10 +03002351}
2352
Olli Etuahof26b27e2018-08-17 11:01:19 +03002353MultiviewRenderTestParams LayeredVertexShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002354{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002355 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, 0,
Olli Etuahof26b27e2018-08-17 11:01:19 +03002356 VertexShaderD3D11(3, 0));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002357}
2358
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002359MultiviewRenderTestParams LayeredMultisampledVertexShaderOpenGL()
2360{
2361 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, 2,
2362 VertexShaderOpenGL(3, 1));
2363}
2364
2365MultiviewRenderTestParams LayeredMultisampledVertexShaderD3D11()
2366{
2367 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, 2,
2368 VertexShaderD3D11(3, 1));
2369}
2370
Jamie Madill04c084d2018-08-08 15:49:28 -04002371ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest,
Olli Etuaho44ae8992018-08-20 15:37:09 +03002372 VertexShaderOpenGL(3, 1),
2373 VertexShaderD3D11(3, 1));
Martin Radevced5c862017-08-17 16:05:29 +03002374ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002375 SideBySideVertexShaderOpenGL(),
2376 LayeredVertexShaderOpenGL(),
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002377 LayeredMultisampledVertexShaderOpenGL(),
Martin Radevc1d4e552017-08-21 12:01:10 +03002378 SideBySideGeomShaderD3D11(),
2379 SideBySideVertexShaderD3D11(),
2380 LayeredGeomShaderD3D11(),
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002381 LayeredVertexShaderD3D11(),
2382 LayeredMultisampledVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002383ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002384 SideBySideVertexShaderOpenGL(),
2385 LayeredVertexShaderOpenGL(),
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002386 LayeredMultisampledVertexShaderOpenGL(),
Martin Radevc1d4e552017-08-21 12:01:10 +03002387 SideBySideGeomShaderD3D11(),
2388 SideBySideVertexShaderD3D11(),
2389 LayeredGeomShaderD3D11(),
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002390 LayeredVertexShaderD3D11(),
2391 LayeredMultisampledVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002392ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002393 SideBySideVertexShaderOpenGL(),
2394 LayeredVertexShaderOpenGL(),
2395 SideBySideGeomShaderD3D11(),
2396 SideBySideVertexShaderD3D11(),
2397 LayeredGeomShaderD3D11(),
2398 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002399ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
Olli Etuaho4bcaf992018-08-17 17:18:28 +03002400 VertexShaderOpenGL(3, 0),
2401 GeomShaderD3D11(3, 0),
2402 VertexShaderD3D11(3, 0));
Martin Radevced5c862017-08-17 16:05:29 +03002403ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002404 SideBySideVertexShaderOpenGL(),
2405 LayeredVertexShaderOpenGL(),
2406 SideBySideGeomShaderD3D11(),
2407 SideBySideVertexShaderD3D11(),
2408 LayeredGeomShaderD3D11(),
2409 LayeredVertexShaderD3D11());
Jamie Madill04c084d2018-08-08 15:49:28 -04002410ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest,
2411 VertexShaderOpenGL(3, 0),
2412 GeomShaderD3D11(3, 0));
2413ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, VertexShaderOpenGL(3, 0), GeomShaderD3D11(3, 0));