blob: 6e7e3f2f54f347f66d3604f523c1bff61ef08aa7 [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,
40 const MultiviewImplementationParams &implementationParams)
Martin Radevc1d4e552017-08-21 12:01:10 +030041 : MultiviewImplementationParams(implementationParams), mMultiviewLayout(multiviewLayout)
Martin Radev3c25ad02017-08-22 17:36:53 +030042 {
43 ASSERT(multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE ||
44 multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
45 }
46 GLenum mMultiviewLayout;
47};
48
Olli Etuahof26b27e2018-08-17 11:01:19 +030049std::ostream &operator<<(std::ostream &os, const MultiviewRenderTestParams &params)
Martin Radev3c25ad02017-08-22 17:36:53 +030050{
Martin Radevc1d4e552017-08-21 12:01:10 +030051 const MultiviewImplementationParams &base =
52 static_cast<const MultiviewImplementationParams &>(params);
Martin Radev3c25ad02017-08-22 17:36:53 +030053 os << base;
54 switch (params.mMultiviewLayout)
55 {
56 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
57 os << "_layered";
58 break;
59 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
60 os << "_side_by_side";
61 break;
62 default:
63 UNREACHABLE();
64 }
65 return os;
66}
67
Olli Etuaho4836acc2018-08-20 15:23:18 +030068class MultiviewFramebufferTestBase : public MultiviewTestBase
Martin Radev8f276e22017-05-30 12:05:52 +030069{
70 protected:
Olli Etuaho4836acc2018-08-20 15:23:18 +030071 MultiviewFramebufferTestBase(const PlatformParameters &params, GLenum multiviewLayout)
Olli Etuahof26b27e2018-08-17 11:01:19 +030072 : MultiviewTestBase(params),
Martin Radev3c25ad02017-08-22 17:36:53 +030073 mViewWidth(0),
74 mViewHeight(0),
Olli Etuaho4836acc2018-08-20 15:23:18 +030075 mNumViews(0),
Olli Etuaho44ae8992018-08-20 15:37:09 +030076 mColorTexture(0u),
77 mDepthTexture(0u),
78 mDrawFramebuffer(0u),
Olli Etuaho4836acc2018-08-20 15:23:18 +030079 mMultiviewLayout(multiviewLayout)
Martin Radev8f276e22017-05-30 12:05:52 +030080 {
Martin Radev3c25ad02017-08-22 17:36:53 +030081 }
Olli Etuaho44ae8992018-08-20 15:37:09 +030082
Olli Etuaho4836acc2018-08-20 15:23:18 +030083 void FramebufferTestSetUp() { MultiviewTestBase::MultiviewTestBaseSetUp(); }
Olli Etuaho44ae8992018-08-20 15:37:09 +030084
85 void FramebufferTestTearDown()
86 {
87 freeFBOs();
88 MultiviewTestBase::MultiviewTestBaseTearDown();
89 }
90
Olli Etuaho4836acc2018-08-20 15:23:18 +030091 void updateFBOs(int viewWidth, int height, int numViews, int numLayers, int baseViewIndex)
Martin Radev3c25ad02017-08-22 17:36:53 +030092 {
Martin Radev72b4e1e2017-08-31 15:42:56 +030093 ASSERT(numViews + baseViewIndex <= numLayers);
94
Olli Etuaho44ae8992018-08-20 15:37:09 +030095 freeFBOs();
96
Martin Radev3c25ad02017-08-22 17:36:53 +030097 mViewWidth = viewWidth;
98 mViewHeight = height;
99 mNumViews = numViews;
Martin Radev8f276e22017-05-30 12:05:52 +0300100
Olli Etuaho44ae8992018-08-20 15:37:09 +0300101 glGenTextures(1, &mColorTexture);
102 glGenTextures(1, &mDepthTexture);
Martin Radev0abb7a22017-08-28 15:34:45 +0300103
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300104 CreateMultiviewBackingTextures(mMultiviewLayout, viewWidth, height, numLayers,
105 mColorTexture, mDepthTexture, 0u);
Martin Radev3c25ad02017-08-22 17:36:53 +0300106
Olli Etuaho44ae8992018-08-20 15:37:09 +0300107 glGenFramebuffers(1, &mDrawFramebuffer);
108
Martin Radev3c25ad02017-08-22 17:36:53 +0300109 // Create draw framebuffer to be used for multiview rendering.
110 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300111 AttachMultiviewTextures(GL_DRAW_FRAMEBUFFER, mMultiviewLayout, viewWidth, numViews,
112 baseViewIndex, mColorTexture, mDepthTexture, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300113
Martin Radev8f276e22017-05-30 12:05:52 +0300114 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
115
116 // Create read framebuffer to be used to retrieve the pixel information for testing
117 // purposes.
Martin Radev3c25ad02017-08-22 17:36:53 +0300118 switch (mMultiviewLayout)
119 {
120 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
121 mReadFramebuffer.resize(1);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300122 glGenFramebuffers(1, mReadFramebuffer.data());
Martin Radev3c25ad02017-08-22 17:36:53 +0300123 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
124 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
125 mColorTexture, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300126 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
127 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300128 break;
129 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
Martin Radev72b4e1e2017-08-31 15:42:56 +0300130 mReadFramebuffer.resize(numLayers);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300131 glGenFramebuffers(mReadFramebuffer.size(), mReadFramebuffer.data());
Martin Radev72b4e1e2017-08-31 15:42:56 +0300132 for (int i = 0; i < numLayers; ++i)
Martin Radev3c25ad02017-08-22 17:36:53 +0300133 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300134 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
135 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
136 mColorTexture, 0, i);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300137 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
138 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300139 }
140 break;
141 default:
142 UNREACHABLE();
143 }
Martin Radev8f276e22017-05-30 12:05:52 +0300144
145 // Clear the buffers.
Martin Radev3c25ad02017-08-22 17:36:53 +0300146 glViewport(0, 0, viewWidth, height);
147 if (mMultiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
148 {
149 // Enable the scissor test only for side-by-side framebuffers.
150 glEnable(GL_SCISSOR_TEST);
151 glScissor(0, 0, viewWidth, height);
152 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300153 }
Martin Radev8f276e22017-05-30 12:05:52 +0300154
Olli Etuaho4836acc2018-08-20 15:23:18 +0300155 void updateFBOs(int viewWidth, int height, int numViews)
Martin Radev72b4e1e2017-08-31 15:42:56 +0300156 {
Olli Etuaho4836acc2018-08-20 15:23:18 +0300157 updateFBOs(viewWidth, height, numViews, numViews, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300158 }
159
Olli Etuaho4836acc2018-08-20 15:23:18 +0300160 void bindMemberDrawFramebuffer() { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer); }
161
Martin Radev3c25ad02017-08-22 17:36:53 +0300162 GLColor GetViewColor(int x, int y, int view)
163 {
164 switch (mMultiviewLayout)
165 {
166 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300167 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
Martin Radev3c25ad02017-08-22 17:36:53 +0300168 return ReadColor(view * mViewWidth + x, y);
169 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
170 ASSERT(static_cast<size_t>(view) < mReadFramebuffer.size());
171 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
172 return ReadColor(x, y);
173 default:
174 UNREACHABLE();
175 }
176 return GLColor(0, 0, 0, 0);
Martin Radev8f276e22017-05-30 12:05:52 +0300177 }
178
Martin Radev3c25ad02017-08-22 17:36:53 +0300179 int mViewWidth;
180 int mViewHeight;
181 int mNumViews;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300182
Olli Etuaho44ae8992018-08-20 15:37:09 +0300183 GLuint mColorTexture;
184 GLuint mDepthTexture;
185
Olli Etuaho4836acc2018-08-20 15:23:18 +0300186 private:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300187 GLuint mDrawFramebuffer;
188 std::vector<GLuint> mReadFramebuffer;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300189 GLenum mMultiviewLayout;
Olli Etuaho44ae8992018-08-20 15:37:09 +0300190
191 void freeFBOs()
192 {
193 if (mDrawFramebuffer)
194 {
195 glDeleteFramebuffers(1, &mDrawFramebuffer);
196 mDrawFramebuffer = 0;
197 }
198 if (!mReadFramebuffer.empty())
199 {
200 glDeleteFramebuffers(mReadFramebuffer.size(), mReadFramebuffer.data());
201 mReadFramebuffer.clear();
202 }
203 if (mDepthTexture)
204 {
205 glDeleteTextures(1, &mDepthTexture);
206 mDepthTexture = 0;
207 }
208 if (mColorTexture)
209 {
210 glDeleteTextures(1, &mColorTexture);
211 mColorTexture = 0;
212 }
213 }
Martin Radev8f276e22017-05-30 12:05:52 +0300214};
215
Olli Etuaho4836acc2018-08-20 15:23:18 +0300216class MultiviewRenderTest : public MultiviewFramebufferTestBase,
Olli Etuahof26b27e2018-08-17 11:01:19 +0300217 public ::testing::TestWithParam<MultiviewRenderTestParams>
Martin Radev8f276e22017-05-30 12:05:52 +0300218{
219 protected:
Olli Etuaho4836acc2018-08-20 15:23:18 +0300220 MultiviewRenderTest() : MultiviewFramebufferTestBase(GetParam(), GetParam().mMultiviewLayout) {}
221 void SetUp() override { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300222 void TearDown() override { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
Martin Radevc1d4e552017-08-21 12:01:10 +0300223
224 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
225 {
226 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
227 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300228};
229
Jamie Madill04c084d2018-08-08 15:49:28 -0400230constexpr char kDualViewVSSource[] = R"(#version 300 es
231#extension GL_OVR_multiview : require
232layout(num_views = 2) in;
233in vec4 vPosition;
234void main()
235{
236 gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x*0.5 + 0.5 : vPosition.x*0.5);
237 gl_Position.yzw = vPosition.yzw;
238})";
239
240constexpr char kDualViewFSSource[] = R"(#version 300 es
241#extension GL_OVR_multiview : require
242precision mediump float;
243out vec4 col;
244void main()
245{
246 col = vec4(0,1,0,1);
247})";
248
Martin Radev3c25ad02017-08-22 17:36:53 +0300249class MultiviewRenderDualViewTest : public MultiviewRenderTest
250{
251 protected:
252 MultiviewRenderDualViewTest() : mProgram(0u) {}
Martin Radev8f276e22017-05-30 12:05:52 +0300253
254 void SetUp() override
255 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300256 MultiviewRenderTest::SetUp();
Martin Radev8f276e22017-05-30 12:05:52 +0300257
258 if (!requestMultiviewExtension())
259 {
260 return;
261 }
262
Olli Etuaho4836acc2018-08-20 15:23:18 +0300263 updateFBOs(2, 1, 2);
Jamie Madill04c084d2018-08-08 15:49:28 -0400264 mProgram = CompileProgram(kDualViewVSSource, kDualViewFSSource);
Martin Radev61bd9992017-08-11 13:10:55 +0300265 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300266 glUseProgram(mProgram);
267 ASSERT_GL_NO_ERROR();
268 }
269
Olli Etuaho44ae8992018-08-20 15:37:09 +0300270 void TearDown() override
271 {
272 if (mProgram != 0u)
273 {
274 glDeleteProgram(mProgram);
275 mProgram = 0u;
276 }
277
278 MultiviewRenderTest::TearDown();
279 }
280
Martin Radev8f276e22017-05-30 12:05:52 +0300281 void checkOutput()
282 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300283 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +0300284 EXPECT_EQ(GLColor::green, GetViewColor(1, 0, 0));
285 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300286 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(1, 0, 1));
Martin Radev8f276e22017-05-30 12:05:52 +0300287 }
288
289 GLuint mProgram;
290};
291
Olli Etuaho44ae8992018-08-20 15:37:09 +0300292// Base class for tests that care mostly about draw call validity and not rendering results.
293class MultiviewDrawValidationTest : public MultiviewTest
Jamie Madill04c084d2018-08-08 15:49:28 -0400294{
295 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300296 MultiviewDrawValidationTest() : MultiviewTest() {}
Jamie Madill04c084d2018-08-08 15:49:28 -0400297
Olli Etuaho44ae8992018-08-20 15:37:09 +0300298 void initOnePixelColorTexture2D(GLuint texId)
Jamie Madill04c084d2018-08-08 15:49:28 -0400299 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300300 glBindTexture(GL_TEXTURE_2D, texId);
Jamie Madill04c084d2018-08-08 15:49:28 -0400301 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300302 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400303
Olli Etuaho44ae8992018-08-20 15:37:09 +0300304 // This initializes a simple VAO with a valid vertex buffer and index buffer with three
305 // vertices.
306 void initVAO(GLuint vao, GLuint vertexBuffer, GLuint indexBuffer)
307 {
308 glBindVertexArray(vao);
Jamie Madill04c084d2018-08-08 15:49:28 -0400309
310 const float kVertexData[3] = {0.0f};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300311 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400312 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
313
314 const unsigned int kIndices[3] = {0u, 1u, 2u};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300315 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400316 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
317 GL_STATIC_DRAW);
318 ASSERT_GL_NO_ERROR();
319 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400320};
321
Martin Radev3c25ad02017-08-22 17:36:53 +0300322class MultiviewOcclusionQueryTest : public MultiviewRenderTest
Martin Radev0d671c92017-08-10 16:41:52 +0300323{
324 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300325 MultiviewOcclusionQueryTest() {}
Martin Radev0d671c92017-08-10 16:41:52 +0300326
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400327 bool requestOcclusionQueryExtension()
328 {
329 if (extensionRequestable("GL_EXT_occlusion_query_boolean"))
330 {
331 glRequestExtensionANGLE("GL_EXT_occlusion_query_boolean");
332 }
333
334 if (!extensionEnabled("GL_EXT_occlusion_query_boolean"))
335 {
336 std::cout << "Test skipped due to missing GL_EXT_occlusion_query_boolean." << std::endl;
337 return false;
338 }
339 return true;
340 }
341
Martin Radev0d671c92017-08-10 16:41:52 +0300342 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
343 {
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400344 GLQueryEXT query;
345 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED, query);
Martin Radev0d671c92017-08-10 16:41:52 +0300346 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
347 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
348
349 GLuint result = GL_TRUE;
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400350 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT, &result);
Martin Radev0d671c92017-08-10 16:41:52 +0300351 return result;
352 }
353};
354
Olli Etuaho4bcaf992018-08-17 17:18:28 +0300355class MultiviewProgramGenerationTest : public MultiviewTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300356{
357 protected:
358 MultiviewProgramGenerationTest() {}
359};
360
Martin Radev3c25ad02017-08-22 17:36:53 +0300361class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300362{
363 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300364 MultiviewRenderPrimitiveTest() : mVBO(0u) {}
365
366 void SetUp() override
367 {
368 MultiviewRenderTest::SetUp();
369 glGenBuffers(1, &mVBO);
370 }
371
372 void TearDown() override
373 {
374 if (mVBO)
375 {
376 glDeleteBuffers(1, &mVBO);
377 mVBO = 0u;
378 }
379 MultiviewRenderTest::TearDown();
380 }
Martin Radev61bd9992017-08-11 13:10:55 +0300381
382 void setupGeometry(const std::vector<Vector2> &vertexData)
383 {
Martin Radev61bd9992017-08-11 13:10:55 +0300384 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
385 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
386 GL_STATIC_DRAW);
387 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500388 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +0300389 }
390
Martin Radev67a8a012017-09-08 13:03:52 +0300391 void checkGreenChannel(const GLubyte expectedGreenChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300392 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300393 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300394 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300395 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300396 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300397 for (int h = 0; h < mViewHeight; ++h)
398 {
399 size_t flatIndex =
400 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300401 EXPECT_EQ(GLColor(0, expectedGreenChannelData[flatIndex], 0,
402 expectedGreenChannelData[flatIndex]),
Martin Radev3c25ad02017-08-22 17:36:53 +0300403 GetViewColor(w, h, view));
404 }
Martin Radev61bd9992017-08-11 13:10:55 +0300405 }
406 }
407 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300408 GLuint mVBO;
Martin Radev61bd9992017-08-11 13:10:55 +0300409};
410
Olli Etuaho4836acc2018-08-20 15:23:18 +0300411class MultiviewSideBySideRenderTest : public MultiviewFramebufferTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300412 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev3c25ad02017-08-22 17:36:53 +0300413{
414 protected:
415 MultiviewSideBySideRenderTest()
Olli Etuaho4836acc2018-08-20 15:23:18 +0300416 : MultiviewFramebufferTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
Martin Radev3c25ad02017-08-22 17:36:53 +0300417 {
418 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300419
420 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
421 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
422 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
Martin Radevc1d4e552017-08-21 12:01:10 +0300423 {
424 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
425 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300426};
427
Olli Etuaho4836acc2018-08-20 15:23:18 +0300428class MultiviewLayeredRenderTest : public MultiviewFramebufferTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300429 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev72b4e1e2017-08-31 15:42:56 +0300430{
431 protected:
432 MultiviewLayeredRenderTest()
Olli Etuaho4836acc2018-08-20 15:23:18 +0300433 : MultiviewFramebufferTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE)
Martin Radev72b4e1e2017-08-31 15:42:56 +0300434 {
435 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300436 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
437 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
438 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
Martin Radevc1d4e552017-08-21 12:01:10 +0300439 {
440 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
441 }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300442};
443
Martin Radev14a26ae2017-07-24 15:56:29 +0300444// The test verifies that glDraw*Indirect:
445// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
446// than 1.
447// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +0300448TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300449{
450 if (!requestMultiviewExtension())
451 {
452 return;
453 }
454
Martin Radev14a26ae2017-07-24 15:56:29 +0300455 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +0300456
457 const std::string fsSource =
458 "#version 300 es\n"
459 "#extension GL_OVR_multiview : require\n"
460 "precision mediump float;\n"
461 "void main()\n"
462 "{}\n";
463
Olli Etuaho44ae8992018-08-20 15:37:09 +0300464 GLVertexArray vao;
465 GLBuffer vertexBuffer;
466 GLBuffer indexBuffer;
467 initVAO(vao, vertexBuffer, indexBuffer);
468
469 GLFramebuffer fbo;
470 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
471
Martin Radev14a26ae2017-07-24 15:56:29 +0300472 GLBuffer commandBuffer;
473 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
474 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
475 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
476 ASSERT_GL_NO_ERROR();
477
Olli Etuaho44ae8992018-08-20 15:37:09 +0300478 GLTexture tex2D;
479 initOnePixelColorTexture2D(tex2D);
480
Martin Radev14a26ae2017-07-24 15:56:29 +0300481 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
482 {
483 const std::string &vsSource =
484 "#version 300 es\n"
485 "#extension GL_OVR_multiview : require\n"
486 "layout(num_views = 2) in;\n"
487 "void main()\n"
488 "{}\n";
489 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
490 glUseProgram(program);
491
Olli Etuaho44ae8992018-08-20 15:37:09 +0300492 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
493 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300494
495 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
496 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
497
498 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
499 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
500 }
501
502 // Check that no errors are generated if the number of views is 1.
503 {
504 const std::string &vsSource =
505 "#version 300 es\n"
506 "#extension GL_OVR_multiview : require\n"
507 "layout(num_views = 1) in;\n"
508 "void main()\n"
509 "{}\n";
510 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
511 glUseProgram(program);
512
Olli Etuaho44ae8992018-08-20 15:37:09 +0300513 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
514 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300515
516 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
517 EXPECT_GL_NO_ERROR();
518
519 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
520 EXPECT_GL_NO_ERROR();
521 }
522}
523
Martin Radev7cf61662017-07-26 17:10:53 +0300524// The test verifies that glDraw*:
525// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
526// program differs.
527// 2) does not generate any error if the number of views is the same.
Martin Radev7cf61662017-07-26 17:10:53 +0300528TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
529{
530 if (!requestMultiviewExtension())
531 {
532 return;
533 }
534
535 const GLint viewportOffsets[4] = {0, 0, 2, 0};
536
537 const std::string &vsSource =
538 "#version 300 es\n"
539 "#extension GL_OVR_multiview : require\n"
540 "layout(num_views = 2) in;\n"
541 "void main()\n"
542 "{}\n";
543 const std::string &fsSource =
544 "#version 300 es\n"
545 "#extension GL_OVR_multiview : require\n"
546 "precision mediump float;\n"
547 "void main()\n"
548 "{}\n";
549 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
550 glUseProgram(program);
551
Olli Etuaho44ae8992018-08-20 15:37:09 +0300552 GLVertexArray vao;
553 GLBuffer vertexBuffer;
554 GLBuffer indexBuffer;
555 initVAO(vao, vertexBuffer, indexBuffer);
556
557 GLFramebuffer fbo;
558 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
559
560 GLTexture tex2D;
561 initOnePixelColorTexture2D(tex2D);
562
Martin Radev7cf61662017-07-26 17:10:53 +0300563 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
564 // number of views.
565 {
566 // The framebuffer has only 1 view.
Olli Etuaho44ae8992018-08-20 15:37:09 +0300567 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
568 1, &viewportOffsets[0]);
Martin Radev7cf61662017-07-26 17:10:53 +0300569
570 glDrawArrays(GL_TRIANGLES, 0, 3);
571 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
572
573 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
574 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
575 }
576
577 // Check that no errors are generated if the number of views in both program and draw
578 // framebuffer matches.
579 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300580 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
581 2, &viewportOffsets[0]);
Martin Radev7cf61662017-07-26 17:10:53 +0300582
583 glDrawArrays(GL_TRIANGLES, 0, 3);
584 EXPECT_GL_NO_ERROR();
585
586 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
587 EXPECT_GL_NO_ERROR();
588 }
Martin Radevda8e2572017-09-12 17:21:16 +0300589}
Martin Radev7cf61662017-07-26 17:10:53 +0300590
Martin Radevda8e2572017-09-12 17:21:16 +0300591// The test verifies that glDraw* generates an INVALID_OPERATION error if the program does not use
592// the multiview extension, but the active draw framebuffer has more than one view.
593TEST_P(MultiviewDrawValidationTest, NumViewsMismatchForNonMultiviewProgram)
594{
595 if (!requestMultiviewExtension())
Martin Radev7cf61662017-07-26 17:10:53 +0300596 {
Martin Radevda8e2572017-09-12 17:21:16 +0300597 return;
Martin Radev7cf61662017-07-26 17:10:53 +0300598 }
Martin Radevda8e2572017-09-12 17:21:16 +0300599
600 const std::string &vsSourceNoMultiview =
601 "#version 300 es\n"
602 "void main()\n"
603 "{}\n";
604 const std::string &fsSourceNoMultiview =
605 "#version 300 es\n"
606 "precision mediump float;\n"
607 "void main()\n"
608 "{}\n";
609 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
610 glUseProgram(programNoMultiview);
611
Olli Etuaho44ae8992018-08-20 15:37:09 +0300612 GLVertexArray vao;
613 GLBuffer vertexBuffer;
614 GLBuffer indexBuffer;
615 initVAO(vao, vertexBuffer, indexBuffer);
616
617 GLFramebuffer fbo;
618 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
619
620 GLTexture tex2D;
621 initOnePixelColorTexture2D(tex2D);
622
Martin Radevda8e2572017-09-12 17:21:16 +0300623 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300624 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 2,
Martin Radevda8e2572017-09-12 17:21:16 +0300625 &viewportOffsets[0]);
626
627 glDrawArrays(GL_TRIANGLES, 0, 3);
628 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
629
630 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
631 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radev7cf61662017-07-26 17:10:53 +0300632}
633
Martin Radev7e69f762017-07-27 14:54:13 +0300634// The test verifies that glDraw*:
635// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
636// greater than 1 and there is an active transform feedback object.
637// 2) does not generate any error if the number of views in the draw framebuffer is 1.
638TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
639{
640 if (!requestMultiviewExtension())
641 {
642 return;
643 }
644
645 const GLint viewportOffsets[4] = {0, 0, 2, 0};
646
647 const std::string &vsSource =
Olli Etuaho3755c482017-10-13 15:40:26 +0300648 R"(#version 300 es
649 out float tfVarying;
650 void main()
651 {
652 tfVarying = 1.0;
653 })";
Martin Radev7e69f762017-07-27 14:54:13 +0300654 const std::string &fsSource =
Olli Etuaho3755c482017-10-13 15:40:26 +0300655 R"(#version 300 es
656 precision mediump float;
657 void main()
658 {})";
Jamie Madill04c084d2018-08-08 15:49:28 -0400659
Olli Etuaho3755c482017-10-13 15:40:26 +0300660 std::vector<std::string> tfVaryings;
Jamie Madill04c084d2018-08-08 15:49:28 -0400661 tfVaryings.emplace_back("tfVarying");
662 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(singleViewProgram, vsSource, fsSource, tfVaryings,
Olli Etuaho3755c482017-10-13 15:40:26 +0300663 GL_SEPARATE_ATTRIBS);
Jamie Madill04c084d2018-08-08 15:49:28 -0400664
665 std::vector<std::string> dualViewTFVaryings;
666 dualViewTFVaryings.emplace_back("gl_Position");
667 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(dualViewProgram, kDualViewVSSource, kDualViewFSSource,
668 dualViewTFVaryings, GL_SEPARATE_ATTRIBS);
Martin Radev7e69f762017-07-27 14:54:13 +0300669
Olli Etuaho44ae8992018-08-20 15:37:09 +0300670 GLVertexArray vao;
671 GLBuffer vertexBuffer;
672 GLBuffer indexBuffer;
673 initVAO(vao, vertexBuffer, indexBuffer);
674
Martin Radev7e69f762017-07-27 14:54:13 +0300675 GLBuffer tbo;
676 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
Jamie Madill04c084d2018-08-08 15:49:28 -0400677 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 16u, nullptr, GL_STATIC_DRAW);
Martin Radev7e69f762017-07-27 14:54:13 +0300678
679 GLTransformFeedback transformFeedback;
680 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
Olli Etuaho3755c482017-10-13 15:40:26 +0300681
682 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
683
Jamie Madill04c084d2018-08-08 15:49:28 -0400684 glUseProgram(dualViewProgram);
Martin Radev7e69f762017-07-27 14:54:13 +0300685 glBeginTransformFeedback(GL_TRIANGLES);
686 ASSERT_GL_NO_ERROR();
687
Olli Etuaho44ae8992018-08-20 15:37:09 +0300688 GLFramebuffer fbo;
689 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
690
691 GLTexture tex2D;
692 initOnePixelColorTexture2D(tex2D);
693
Martin Radev7e69f762017-07-27 14:54:13 +0300694 // Check that drawArrays generates an error when there is an active transform feedback object
695 // and the number of views in the draw framebuffer is greater than 1.
696 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300697 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
698 2, &viewportOffsets[0]);
Martin Radev7e69f762017-07-27 14:54:13 +0300699 glDrawArrays(GL_TRIANGLES, 0, 3);
700 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
701 }
702
Jamie Madill04c084d2018-08-08 15:49:28 -0400703 glEndTransformFeedback();
704
705 // Ending transform feedback should allow the draw to succeed.
706 {
707 glDrawArrays(GL_TRIANGLES, 0, 3);
708 EXPECT_GL_NO_ERROR();
709 }
710
711 // A paused transform feedback should still trigger an error.
712 glBeginTransformFeedback(GL_TRIANGLES);
713 glPauseTransformFeedback();
714 ASSERT_GL_NO_ERROR();
715
716 glDrawArrays(GL_TRIANGLES, 0, 3);
717 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
718
719 // Unbind transform feedback - should succeed.
720 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
721 glDrawArrays(GL_TRIANGLES, 0, 3);
722 ASSERT_GL_NO_ERROR();
723
724 // Rebind paused transform feedback - should fail.
725 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
726 glDrawArrays(GL_TRIANGLES, 0, 3);
727 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
728
729 glResumeTransformFeedback();
730 glEndTransformFeedback();
731
732 glUseProgram(singleViewProgram);
733 glBeginTransformFeedback(GL_TRIANGLES);
734 ASSERT_GL_NO_ERROR();
735
Martin Radev7e69f762017-07-27 14:54:13 +0300736 // Check that drawArrays does not generate an error when the number of views in the draw
737 // framebuffer is 1.
738 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300739 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
740 1, &viewportOffsets[0]);
Martin Radev7e69f762017-07-27 14:54:13 +0300741 glDrawArrays(GL_TRIANGLES, 0, 3);
742 EXPECT_GL_NO_ERROR();
743 }
744
745 glEndTransformFeedback();
746}
747
Martin Radevffe754b2017-07-31 10:38:07 +0300748// The test verifies that glDraw*:
749// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
750// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
751// 2) does not generate any error if the number of views in the draw framebuffer is 1.
752TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
753{
Yunchao He9550c602018-02-13 14:47:05 +0800754 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radevffe754b2017-07-31 10:38:07 +0300755
Olli Etuaho94c91a92018-07-19 15:10:24 +0300756 if (extensionRequestable("GL_EXT_disjoint_timer_query"))
757 {
758 glRequestExtensionANGLE("GL_EXT_disjoint_timer_query");
759 }
760
Yunchao He9550c602018-02-13 14:47:05 +0800761 ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_disjoint_timer_query"));
Martin Radevffe754b2017-07-31 10:38:07 +0300762
Olli Etuaho44ae8992018-08-20 15:37:09 +0300763 ANGLE_GL_PROGRAM(dualViewProgram, kDualViewVSSource, kDualViewFSSource);
764
Martin Radevffe754b2017-07-31 10:38:07 +0300765 const GLint viewportOffsets[4] = {0, 0, 2, 0};
766 const std::string &vsSource =
767 "#version 300 es\n"
768 "void main()\n"
769 "{}\n";
770 const std::string &fsSource =
771 "#version 300 es\n"
772 "precision mediump float;\n"
773 "void main()\n"
774 "{}\n";
Jamie Madill04c084d2018-08-08 15:49:28 -0400775 ANGLE_GL_PROGRAM(singleViewProgram, vsSource, fsSource);
776 glUseProgram(singleViewProgram);
Martin Radevffe754b2017-07-31 10:38:07 +0300777
Olli Etuaho44ae8992018-08-20 15:37:09 +0300778 GLVertexArray vao;
779 GLBuffer vertexBuffer;
780 GLBuffer indexBuffer;
781 initVAO(vao, vertexBuffer, indexBuffer);
782
Martin Radevffe754b2017-07-31 10:38:07 +0300783 GLuint query = 0u;
784 glGenQueriesEXT(1, &query);
785 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
786
Olli Etuaho44ae8992018-08-20 15:37:09 +0300787 GLFramebuffer fbo;
788 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
789
790 GLTexture tex2D;
791 initOnePixelColorTexture2D(tex2D);
792
Martin Radevffe754b2017-07-31 10:38:07 +0300793 // Check first case.
794 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300795 glUseProgram(dualViewProgram);
796 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
797 2, &viewportOffsets[0]);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300798 glClear(GL_COLOR_BUFFER_BIT);
799 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radevffe754b2017-07-31 10:38:07 +0300800 glDrawArrays(GL_TRIANGLES, 0, 3);
801 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
802 }
803
804 // Check second case.
805 {
Jamie Madill04c084d2018-08-08 15:49:28 -0400806 glUseProgram(singleViewProgram);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300807 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
808 1, &viewportOffsets[0]);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300809 glClear(GL_COLOR_BUFFER_BIT);
810 EXPECT_GL_NO_ERROR();
Martin Radevffe754b2017-07-31 10:38:07 +0300811 glDrawArrays(GL_TRIANGLES, 0, 3);
812 EXPECT_GL_NO_ERROR();
813 }
814
815 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
816 glDeleteQueries(1, &query);
Jamie Madill04c084d2018-08-08 15:49:28 -0400817
818 // Check starting a query after a successful draw.
819 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300820 glUseProgram(dualViewProgram);
821 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0,
822 2, &viewportOffsets[0]);
Jamie Madill04c084d2018-08-08 15:49:28 -0400823 glClear(GL_COLOR_BUFFER_BIT);
824 EXPECT_GL_NO_ERROR();
825 glDrawArrays(GL_TRIANGLES, 0, 3);
826 EXPECT_GL_NO_ERROR();
827
828 glGenQueriesEXT(1, &query);
829 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
830
831 glDrawArrays(GL_TRIANGLES, 0, 3);
832 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
833
834 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
835 glDrawArrays(GL_TRIANGLES, 0, 3);
836 EXPECT_GL_NO_ERROR();
837
838 glDeleteQueries(1, &query);
839 }
Martin Radevffe754b2017-07-31 10:38:07 +0300840}
841
Martin Radev8f276e22017-05-30 12:05:52 +0300842// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300843TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300844{
845 if (!requestMultiviewExtension())
846 {
847 return;
848 }
849 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
850 ASSERT_GL_NO_ERROR();
851
852 checkOutput();
853}
854
855// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300856TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300857{
858 if (!requestMultiviewExtension())
859 {
860 return;
861 }
862 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
863 ASSERT_GL_NO_ERROR();
864
865 checkOutput();
866}
867
868// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300869TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300870{
871 if (!requestMultiviewExtension())
872 {
873 return;
874 }
875 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
876 ASSERT_GL_NO_ERROR();
877
878 checkOutput();
879}
880
881// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300882TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300883{
884 if (!requestMultiviewExtension())
885 {
886 return;
887 }
888
889 const std::string vsSource =
890 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300891 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300892 "layout(num_views = 4) in;\n"
893 "in vec4 vPosition;\n"
894 "void main()\n"
895 "{\n"
896 " if (gl_ViewID_OVR == 0u) {\n"
897 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
898 " } else if (gl_ViewID_OVR == 1u) {\n"
899 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
900 " } else if (gl_ViewID_OVR == 2u) {\n"
901 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
902 " } else {\n"
903 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
904 " }"
905 " gl_Position.yzw = vPosition.yzw;\n"
906 "}\n";
907
908 const std::string fsSource =
909 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300910 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300911 "precision mediump float;\n"
912 "out vec4 col;\n"
913 "void main()\n"
914 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300915 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300916 "}\n";
917
Olli Etuaho4836acc2018-08-20 15:23:18 +0300918 updateFBOs(4, 1, 4);
Martin Radev8f276e22017-05-30 12:05:52 +0300919 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +0300920
921 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
922 ASSERT_GL_NO_ERROR();
923
924 for (int i = 0; i < 4; ++i)
925 {
926 for (int j = 0; j < 4; ++j)
927 {
Martin Radev8f276e22017-05-30 12:05:52 +0300928 if (i == j)
929 {
Martin Radev67a8a012017-09-08 13:03:52 +0300930 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300931 }
932 else
933 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300934 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300935 }
936 }
937 }
938 EXPECT_GL_NO_ERROR();
939}
940
941// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300942TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +0300943{
944 if (!requestMultiviewExtension())
945 {
946 return;
947 }
948
949 const std::string vsSource =
950 "#version 300 es\n"
951 "#extension GL_OVR_multiview : require\n"
952 "layout(num_views = 2) in;\n"
953 "in vec4 vPosition;\n"
954 "void main()\n"
955 "{\n"
956 " vec4 p = vPosition;\n"
957 " if (gl_InstanceID == 1){\n"
958 " p.y = .5*p.y + .5;\n"
959 " } else {\n"
960 " p.y = p.y*.5;\n"
961 " }\n"
962 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x*0.5 + 0.5 : p.x*0.5);\n"
963 " gl_Position.yzw = p.yzw;\n"
964 "}\n";
965
966 const std::string fsSource =
967 "#version 300 es\n"
968 "#extension GL_OVR_multiview : require\n"
969 "precision mediump float;\n"
970 "out vec4 col;\n"
971 "void main()\n"
972 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300973 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300974 "}\n";
975
Martin Radev3c25ad02017-08-22 17:36:53 +0300976 const int kViewWidth = 2;
977 const int kViewHeight = 2;
978 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300979 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev8f276e22017-05-30 12:05:52 +0300980 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +0300981
Martin Radev67a8a012017-09-08 13:03:52 +0300982 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 2u);
Martin Radev8f276e22017-05-30 12:05:52 +0300983 ASSERT_GL_NO_ERROR();
984
Martin Radev67a8a012017-09-08 13:03:52 +0300985 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
986 {{255, 0}, {255, 0}}};
Martin Radev3c25ad02017-08-22 17:36:53 +0300987
988 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +0300989 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300990 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +0300991 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300992 for (int x = 0; x < 2; ++x)
993 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300994 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][y][x], 0,
995 expectedGreenChannel[view][y][x]),
Martin Radev3c25ad02017-08-22 17:36:53 +0300996 GetViewColor(x, y, view));
997 }
Martin Radev8f276e22017-05-30 12:05:52 +0300998 }
999 }
1000}
1001
Martin Radev553590a2017-07-31 16:40:39 +03001002// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
1003// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
1004// offset of each quad are passed as separate attributes which are indexed based on the
1005// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
1006// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
1007// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
1008// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +03001009TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +03001010{
1011 if (!requestMultiviewExtension())
1012 {
1013 return;
1014 }
1015
Corentin Wallez02cd1522018-08-22 13:46:21 +02001016 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001017 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001018 if (IsWindows() && IsD3D11())
1019 {
1020 ignoreD3D11SDKLayersWarnings();
1021 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001022
Martin Radev553590a2017-07-31 16:40:39 +03001023 const std::string &vsSource =
1024 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001025 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001026 "layout(num_views = 2) in;\n"
1027 "in vec3 vPosition;\n"
1028 "in float offsetX;\n"
1029 "in float offsetY;\n"
1030 "void main()\n"
1031 "{\n"
1032 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001033 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001034 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
1035 " gl_Position.yzw = p.yzw;\n"
1036 "}\n";
1037
1038 const std::string &fsSource =
1039 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001040 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001041 "precision mediump float;\n"
1042 "out vec4 col;\n"
1043 "void main()\n"
1044 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001045 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001046 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +03001047
1048 const int kViewWidth = 4;
1049 const int kViewHeight = 4;
1050 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001051 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev553590a2017-07-31 16:40:39 +03001052 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev553590a2017-07-31 16:40:39 +03001053
1054 GLBuffer xOffsetVBO;
1055 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1056 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
1057 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
1058 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1059 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1060 glVertexAttribDivisor(xOffsetLoc, 3);
1061 glEnableVertexAttribArray(xOffsetLoc);
1062
1063 GLBuffer yOffsetVBO;
1064 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1065 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1066 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1067 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1068 glVertexAttribDivisor(yOffsetLoc, 1);
1069 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1070 glEnableVertexAttribArray(yOffsetLoc);
1071
Martin Radev67a8a012017-09-08 13:03:52 +03001072 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev553590a2017-07-31 16:40:39 +03001073 ASSERT_GL_NO_ERROR();
1074
Martin Radev67a8a012017-09-08 13:03:52 +03001075 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001076 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1077 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1078 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +03001079 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001080 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +03001081 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001082 for (int col = 0; col < 4; ++col)
1083 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001084 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0,
1085 expectedGreenChannel[view][row][col]),
Martin Radev3c25ad02017-08-22 17:36:53 +03001086 GetViewColor(col, row, view));
1087 }
Martin Radev553590a2017-07-31 16:40:39 +03001088 }
1089 }
1090}
1091
1092// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1093// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +03001094TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +03001095{
1096 if (!requestMultiviewExtension())
1097 {
1098 return;
1099 }
1100
Olli Etuaho4836acc2018-08-20 15:23:18 +03001101 updateFBOs(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +03001102
1103 // Create multiview program.
1104 const std::string &vs =
1105 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001106 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001107 "layout(num_views = 2) in;\n"
1108 "layout(location = 0) in vec2 vPosition;\n"
1109 "layout(location = 1) in float offsetX;\n"
1110 "void main()\n"
1111 "{\n"
1112 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1113 " p.x += offsetX;\n"
1114 " gl_Position = p;\n"
1115 "}\n";
1116
1117 const std::string &fs =
1118 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001119 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001120 "precision mediump float;\n"
1121 "out vec4 col;\n"
1122 "void main()\n"
1123 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001124 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001125 "}\n";
1126
1127 ANGLE_GL_PROGRAM(program, vs, fs);
1128
1129 const std::string &dummyVS =
1130 "#version 300 es\n"
1131 "layout(location = 0) in vec2 vPosition;\n"
1132 "layout(location = 1) in float offsetX;\n"
1133 "void main()\n"
1134 "{\n"
1135 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1136 "}\n";
1137
1138 const std::string &dummyFS =
1139 "#version 300 es\n"
1140 "precision mediump float;\n"
1141 "out vec4 col;\n"
1142 "void main()\n"
1143 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001144 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001145 "}\n";
1146
1147 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
1148
1149 GLBuffer xOffsetVBO;
1150 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1151 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1152 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1153 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1154
1155 GLBuffer vertexVBO;
1156 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1157 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1158 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1159 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1160
1161 GLVertexArray vao[2];
1162 for (size_t i = 0u; i < 2u; ++i)
1163 {
1164 glBindVertexArray(vao[i]);
1165
1166 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1167 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1168 glEnableVertexAttribArray(0);
1169
1170 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1171 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1172 glEnableVertexAttribArray(1);
1173 }
1174 ASSERT_GL_NO_ERROR();
1175
1176 glViewport(0, 0, 1, 1);
1177 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001178 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001179 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001180
1181 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1182 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1183 // bits are cleared.
1184 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001185 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1186 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001187 glBindVertexArray(vao[0]);
1188 glVertexAttribDivisor(1, 0);
1189 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1190 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001191 ASSERT_GL_NO_ERROR();
1192
1193 // Check that vertexAttribDivisor uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001194 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001195 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001196 glUseProgram(program);
1197 glVertexAttribDivisor(1, 1);
1198 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001199 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1200 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001201
1202 // Clear the buffers and propagate divisor to the driver.
1203 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1204 // dirty bits when useProgram is called.
1205 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001206 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1207 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001208 glVertexAttribDivisor(1, 1);
1209 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1210 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001211 ASSERT_GL_NO_ERROR();
1212
1213 // Check that useProgram uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001214 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001215 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001216 glUseProgram(program);
1217 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001218 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1219 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001220
1221 // We go through similar steps as before.
1222 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001223 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1224 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001225 glVertexAttribDivisor(1, 1);
1226 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1227 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001228 ASSERT_GL_NO_ERROR();
1229
1230 // Check that bindVertexArray uses the number of views to update the divisor.
1231 {
1232 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1233 // divisor for vao[1] only.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001234 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001235 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001236 glBindVertexArray(vao[1]);
1237 glUseProgram(program);
1238 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001239 glBindVertexArray(0);
1240 ASSERT_GL_NO_ERROR();
1241 }
1242 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1243 // adjusts the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001244 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001245 glBindVertexArray(vao[0]);
1246 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001247 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1248 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001249}
1250
Martin Radev0d671c92017-08-10 16:41:52 +03001251// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1252// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001253TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001254{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001255 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1256 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001257
1258 const std::string vsSource =
1259 "#version 300 es\n"
1260 "#extension GL_OVR_multiview : require\n"
1261 "layout(num_views = 2) in;\n"
1262 "in vec3 vPosition;\n"
1263 "void main()\n"
1264 "{\n"
1265 " gl_Position.x = 2.0;\n"
1266 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1267 "}\n";
1268
1269 const std::string fsSource =
1270 "#version 300 es\n"
1271 "#extension GL_OVR_multiview : require\n"
1272 "precision mediump float;\n"
1273 "out vec4 col;\n"
1274 "void main()\n"
1275 "{\n"
1276 " col = vec4(1,0,0,0);\n"
1277 "}\n";
1278 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001279 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001280
1281 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1282 ASSERT_GL_NO_ERROR();
1283 EXPECT_GL_FALSE(result);
1284}
1285
1286// Test that there are fragments passing the occlusion query if only view 0 can produce
1287// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001288TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001289{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001290 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1291 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001292
1293 const std::string vsSource =
1294 "#version 300 es\n"
1295 "#extension GL_OVR_multiview : require\n"
1296 "layout(num_views = 2) in;\n"
1297 "in vec3 vPosition;\n"
1298 "void main()\n"
1299 "{\n"
1300 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1301 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1302 "}\n";
1303
1304 const std::string fsSource =
1305 "#version 300 es\n"
1306 "#extension GL_OVR_multiview : require\n"
1307 "precision mediump float;\n"
1308 "out vec4 col;\n"
1309 "void main()\n"
1310 "{\n"
1311 " col = vec4(1,0,0,0);\n"
1312 "}\n";
1313 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001314 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001315
1316 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1317 ASSERT_GL_NO_ERROR();
1318 EXPECT_GL_TRUE(result);
1319}
1320
1321// Test that there are fragments passing the occlusion query if only view 1 can produce
1322// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001323TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001324{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001325 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1326 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001327
1328 const std::string vsSource =
1329 "#version 300 es\n"
1330 "#extension GL_OVR_multiview : require\n"
1331 "layout(num_views = 2) in;\n"
1332 "in vec3 vPosition;\n"
1333 "void main()\n"
1334 "{\n"
1335 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1336 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1337 "}\n";
1338
1339 const std::string fsSource =
1340 "#version 300 es\n"
1341 "#extension GL_OVR_multiview : require\n"
1342 "precision mediump float;\n"
1343 "out vec4 col;\n"
1344 "void main()\n"
1345 "{\n"
1346 " col = vec4(1,0,0,0);\n"
1347 "}\n";
1348 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001349 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001350
1351 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1352 ASSERT_GL_NO_ERROR();
1353 EXPECT_GL_TRUE(result);
1354}
1355
Martin Radev41ac68e2017-06-06 12:16:58 +03001356// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1357// compiles and links without an error.
1358TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1359{
1360 if (!requestMultiviewExtension())
1361 {
1362 return;
1363 }
1364
1365 const std::string vsSource =
1366 "#version 300 es\n"
1367 "#extension GL_OVR_multiview : require\n"
1368 "layout(num_views = 2) in;\n"
1369 "void main()\n"
1370 "{\n"
1371 "}\n";
1372
1373 const std::string fsSource =
1374 "#version 300 es\n"
1375 "#extension GL_OVR_multiview : require\n"
1376 "precision mediump float;\n"
1377 "void main()\n"
1378 "{\n"
1379 "}\n";
1380
1381 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1382 glUseProgram(program);
1383
1384 EXPECT_GL_NO_ERROR();
1385}
1386
1387// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1388// without an error.
1389TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1390{
1391 if (!requestMultiviewExtension())
1392 {
1393 return;
1394 }
1395
1396 const std::string vsSource =
1397 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001398 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001399 "layout(num_views = 2) in;\n"
1400 "void main()\n"
1401 "{\n"
1402 " if (gl_ViewID_OVR == 0u) {\n"
1403 " gl_Position = vec4(1,0,0,1);\n"
1404 " } else {\n"
1405 " gl_Position = vec4(-1,0,0,1);\n"
1406 " }\n"
1407 "}\n";
1408
1409 const std::string fsSource =
1410 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001411 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001412 "precision mediump float;\n"
1413 "void main()\n"
1414 "{\n"
1415 "}\n";
1416
1417 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1418 glUseProgram(program);
1419
1420 EXPECT_GL_NO_ERROR();
1421}
1422
1423// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1424// without an error.
1425TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1426{
1427 if (!requestMultiviewExtension())
1428 {
1429 return;
1430 }
1431
1432 const std::string vsSource =
1433 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001434 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001435 "layout(num_views = 2) in;\n"
1436 "void main()\n"
1437 "{\n"
1438 "}\n";
1439
1440 const std::string fsSource =
1441 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001442 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001443 "precision mediump float;\n"
1444 "out vec4 col;\n"
1445 "void main()\n"
1446 "{\n"
1447 " if (gl_ViewID_OVR == 0u) {\n"
1448 " col = vec4(1,0,0,1);\n"
1449 " } else {\n"
1450 " col = vec4(-1,0,0,1);\n"
1451 " }\n"
1452 "}\n";
1453
1454 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1455 glUseProgram(program);
1456
1457 EXPECT_GL_NO_ERROR();
1458}
1459
Martin Radev61bd9992017-08-11 13:10:55 +03001460// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001461TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001462{
1463 if (!requestMultiviewExtension())
1464 {
1465 return;
1466 }
1467
Geoff Lang25858162017-11-06 11:25:58 -05001468 // Test failing on P400 graphics card (anglebug.com/2228)
1469 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1470
Martin Radev61bd9992017-08-11 13:10:55 +03001471 const std::string vsSource =
1472 "#version 300 es\n"
1473 "#extension GL_OVR_multiview : require\n"
1474 "layout(num_views = 2) in;\n"
1475 "layout(location=0) in vec2 vPosition;\n"
1476 "void main()\n"
1477 "{\n"
1478 " gl_PointSize = 1.0;\n"
1479 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1480 "}\n";
1481
1482 const std::string fsSource =
1483 "#version 300 es\n"
1484 "#extension GL_OVR_multiview : require\n"
1485 "precision mediump float;\n"
1486 "out vec4 col;\n"
1487 "void main()\n"
1488 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001489 " col = vec4(0,1,0,1);\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001490 "}\n";
1491 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1492 glUseProgram(program);
1493
Martin Radev3c25ad02017-08-22 17:36:53 +03001494 const int kViewWidth = 4;
1495 const int kViewHeight = 2;
1496 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001497 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001498
1499 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1500 std::vector<Vector2> vertexDataInClipSpace =
1501 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1502 setupGeometry(vertexDataInClipSpace);
1503
1504 glDrawArrays(GL_POINTS, 0, 2);
1505
Martin Radev67a8a012017-09-08 13:03:52 +03001506 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001507 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001508 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001509}
1510
1511// The test checks that GL_LINES is correctly rendered.
1512// The behavior of this test is not guaranteed by the spec:
1513// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1514// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1515// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1516// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001517TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001518{
1519 if (!requestMultiviewExtension())
1520 {
1521 return;
1522 }
1523
Martin Radevced5c862017-08-17 16:05:29 +03001524 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001525 ASSERT_NE(program, 0u);
1526 glUseProgram(program);
1527 ASSERT_GL_NO_ERROR();
1528
Martin Radev3c25ad02017-08-22 17:36:53 +03001529 const int kViewWidth = 4;
1530 const int kViewHeight = 2;
1531 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001532 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001533
1534 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1535 std::vector<Vector2> vertexDataInClipSpace =
1536 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1537 setupGeometry(vertexDataInClipSpace);
1538
1539 glDrawArrays(GL_LINES, 0, 2);
1540
Martin Radev67a8a012017-09-08 13:03:52 +03001541 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001542 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001543 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001544
1545 glDeleteProgram(program);
1546}
1547
1548// The test checks that GL_LINE_STRIP is correctly rendered.
1549// The behavior of this test is not guaranteed by the spec:
1550// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1551// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1552// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1553// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001554TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001555{
1556 if (!requestMultiviewExtension())
1557 {
1558 return;
1559 }
1560
Martin Radevced5c862017-08-17 16:05:29 +03001561 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001562 ASSERT_NE(program, 0u);
1563 glUseProgram(program);
1564 ASSERT_GL_NO_ERROR();
1565
Martin Radev3c25ad02017-08-22 17:36:53 +03001566 const int kViewWidth = 4;
1567 const int kViewHeight = 2;
1568 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001569 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001570
1571 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1572 std::vector<Vector2> vertexDataInClipSpace =
1573 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1574 setupGeometry(vertexDataInClipSpace);
1575
1576 glDrawArrays(GL_LINE_STRIP, 0, 3);
1577
Martin Radev67a8a012017-09-08 13:03:52 +03001578 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001579 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001580 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001581
1582 glDeleteProgram(program);
1583}
1584
1585// The test checks that GL_LINE_LOOP is correctly rendered.
1586// The behavior of this test is not guaranteed by the spec:
1587// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1588// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1589// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1590// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001591TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001592{
1593 if (!requestMultiviewExtension())
1594 {
1595 return;
1596 }
1597
Martin Radevced5c862017-08-17 16:05:29 +03001598 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001599 ASSERT_NE(program, 0u);
1600 glUseProgram(program);
1601 ASSERT_GL_NO_ERROR();
1602
Martin Radev3c25ad02017-08-22 17:36:53 +03001603 const int kViewWidth = 4;
1604 const int kViewHeight = 4;
1605 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001606 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001607
1608 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1609 Vector2I(0, 3)};
1610 std::vector<Vector2> vertexDataInClipSpace =
1611 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1612 setupGeometry(vertexDataInClipSpace);
1613
1614 glDrawArrays(GL_LINE_LOOP, 0, 4);
1615
Martin Radev67a8a012017-09-08 13:03:52 +03001616 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001617 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1618 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001619 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001620
1621 glDeleteProgram(program);
1622}
1623
1624// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001625TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001626{
1627 if (!requestMultiviewExtension())
1628 {
1629 return;
1630 }
1631
Martin Radevced5c862017-08-17 16:05:29 +03001632 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001633 ASSERT_NE(program, 0u);
1634 glUseProgram(program);
1635 ASSERT_GL_NO_ERROR();
1636
1637 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1638 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1639 setupGeometry(vertexDataInClipSpace);
1640
Martin Radev3c25ad02017-08-22 17:36:53 +03001641 const int kViewWidth = 2;
1642 const int kViewHeight = 2;
1643 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001644 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001645
1646 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1647
Martin Radev67a8a012017-09-08 13:03:52 +03001648 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1649 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1650 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001651
1652 glDeleteProgram(program);
1653}
1654
1655// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001656TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001657{
1658 if (!requestMultiviewExtension())
1659 {
1660 return;
1661 }
1662
Martin Radevced5c862017-08-17 16:05:29 +03001663 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001664 ASSERT_NE(program, 0u);
1665 glUseProgram(program);
1666 ASSERT_GL_NO_ERROR();
1667
1668 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1669 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1670 setupGeometry(vertexDataInClipSpace);
1671
Martin Radev3c25ad02017-08-22 17:36:53 +03001672 const int kViewWidth = 2;
1673 const int kViewHeight = 2;
1674 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001675 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001676
1677 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1678
Martin Radev67a8a012017-09-08 13:03:52 +03001679 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1680 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1681 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001682
1683 glDeleteProgram(program);
1684}
1685
1686// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1687// bounds. The test does not rely on the actual line width being greater than 1.0.
Martin Radev3c25ad02017-08-22 17:36:53 +03001688TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
Martin Radev61bd9992017-08-11 13:10:55 +03001689{
1690 if (!requestMultiviewExtension())
1691 {
1692 return;
1693 }
1694
Olli Etuaho9259fd02018-08-22 12:12:00 +03001695 GLTexture colorTexture;
Martin Radev61bd9992017-08-11 13:10:55 +03001696
Olli Etuaho9259fd02018-08-22 12:12:00 +03001697 CreateMultiviewBackingTextures(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, 2, 1, 2,
1698 colorTexture, 0u, 0u);
1699
1700 GLFramebuffer drawFramebuffer;
1701 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFramebuffer);
Martin Radev61bd9992017-08-11 13:10:55 +03001702 GLint viewportOffsets[4] = {1, 0, 3, 0};
1703 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
Olli Etuaho9259fd02018-08-22 12:12:00 +03001704 colorTexture, 0, 2, &viewportOffsets[0]);
1705
1706 GLFramebuffer readFramebuffer;
1707 glBindFramebuffer(GL_READ_FRAMEBUFFER, readFramebuffer);
1708 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture,
1709 0);
1710
1711 ASSERT_GL_NO_ERROR();
Martin Radev61bd9992017-08-11 13:10:55 +03001712
1713 glViewport(0, 0, 1, 1);
1714 glScissor(0, 0, 1, 1);
1715 glEnable(GL_SCISSOR_TEST);
1716
1717 const std::string vsSource =
1718 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001719 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001720 "layout(num_views = 2) in;\n"
1721 "layout(location=0) in vec2 vPosition;\n"
1722 "void main()\n"
1723 "{\n"
1724 " gl_PointSize = 10.0;\n"
1725 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1726 "}\n";
1727
1728 const std::string fsSource =
1729 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001730 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001731 "precision mediump float;\n"
1732 "out vec4 col;\n"
1733 "void main()\n"
1734 "{\n"
1735 " if (gl_ViewID_OVR == 0u) {\n"
1736 " col = vec4(1,0,0,1);\n"
1737 " } else {\n"
1738 " col = vec4(0,1,0,1);\n"
1739 " }\n"
1740 "}\n";
1741 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1742 glUseProgram(program);
1743
1744 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1745 const std::vector<Vector2> &vertexDataInClipSpace =
1746 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001747
1748 GLBuffer vbo;
1749 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1750 glBufferData(GL_ARRAY_BUFFER, vertexDataInClipSpace.size() * sizeof(Vector2),
1751 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1752 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -05001753 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +03001754
1755 // Test rendering points.
1756 {
1757 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1758 glDrawArrays(GL_POINTS, 0, 2);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001759 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001760 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001761 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001762 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1763 }
1764
1765 // Test rendering lines.
1766 {
1767 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1768 glLineWidth(10.f);
1769 glDrawArrays(GL_LINES, 0, 2);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001770 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001771 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001772 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::transparentBlack);
Martin Radev61bd9992017-08-11 13:10:55 +03001773 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1774 }
1775}
1776
Martin Radev0abb7a22017-08-28 15:34:45 +03001777// Verify that re-linking a program adjusts the attribute divisor.
1778// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1779// to each other. The quads' position and color depend on the corresponding attribute divisors.
1780TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1781{
1782 if (!requestMultiviewExtension())
1783 {
1784 return;
1785 }
1786
Corentin Wallez02cd1522018-08-22 13:46:21 +02001787 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001788 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001789 if (IsWindows() && IsD3D11())
1790 {
1791 ignoreD3D11SDKLayersWarnings();
1792 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001793
Martin Radev0abb7a22017-08-28 15:34:45 +03001794 const int kViewWidth = 4;
1795 const int kViewHeight = 1;
1796 const int kNumViews = 2;
1797
1798 const std::string &fsSource =
1799 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001800 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001801 "precision mediump float;\n"
1802 "in vec4 oColor;\n"
1803 "out vec4 col;\n"
1804 "void main()\n"
1805 "{\n"
1806 " col = oColor;\n"
1807 "}\n";
1808
1809 auto generateVertexShaderSource = [](int numViews) -> std::string {
1810 std::string source =
1811 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001812 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001813 "layout(num_views = " +
1814 ToString(numViews) +
1815 ") in;\n"
1816 "in vec3 vPosition;\n"
1817 "in float vOffsetX;\n"
1818 "in vec4 vColor;\n"
1819 "out vec4 oColor;\n"
1820 "void main()\n"
1821 "{\n"
1822 " vec4 p = vec4(vPosition, 1.);\n"
1823 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1824 " oColor = vColor;\n"
1825 " gl_Position = p;\n"
1826 "}\n";
1827 return source;
1828 };
1829
1830 std::string vsSource = generateVertexShaderSource(kNumViews);
1831 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1832 glUseProgram(program);
1833
1834 GLint positionLoc;
1835 GLBuffer xOffsetVBO;
1836 GLint xOffsetLoc;
1837 GLBuffer colorVBO;
1838 GLint colorLoc;
1839
1840 {
1841 // Initialize buffers and setup attributes.
1842 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1843 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1844 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1845 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1846 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1847 glVertexAttribDivisor(xOffsetLoc, 1);
1848 glEnableVertexAttribArray(xOffsetLoc);
1849
1850 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1851 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1852 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1853 colorLoc = glGetAttribLocation(program, "vColor");
1854 glVertexAttribDivisor(colorLoc, 2);
1855 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1856 glEnableVertexAttribArray(colorLoc);
1857
1858 positionLoc = glGetAttribLocation(program, "vPosition");
1859 }
1860
1861 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001862 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001863
Martin Radev67a8a012017-09-08 13:03:52 +03001864 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001865 ASSERT_GL_NO_ERROR();
1866
1867 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1868 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1869 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1870 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1871 }
1872
1873 {
1874 const int kNewNumViews = 3;
1875 vsSource = generateVertexShaderSource(kNewNumViews);
Olli Etuaho4836acc2018-08-20 15:23:18 +03001876 updateFBOs(kViewWidth, kViewHeight, kNewNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001877
1878 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
1879 ASSERT_NE(0u, vs);
1880 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
1881 ASSERT_NE(0u, fs);
1882
1883 GLint numAttachedShaders = 0;
1884 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1885
1886 GLuint attachedShaders[2] = {0u};
1887 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1888 for (int i = 0; i < 2; ++i)
1889 {
1890 glDetachShader(program, attachedShaders[i]);
1891 }
1892
1893 glAttachShader(program, vs);
1894 glDeleteShader(vs);
1895
1896 glAttachShader(program, fs);
1897 glDeleteShader(fs);
1898
1899 glBindAttribLocation(program, positionLoc, "vPosition");
1900 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1901 glBindAttribLocation(program, colorLoc, "vColor");
1902
1903 glLinkProgram(program);
1904
Martin Radev67a8a012017-09-08 13:03:52 +03001905 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001906 ASSERT_GL_NO_ERROR();
1907
1908 for (int i = 0; i < kNewNumViews; ++i)
1909 {
1910 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1911 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1912 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1913 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1914 }
1915 }
1916}
1917
Martin Radevced5c862017-08-17 16:05:29 +03001918// Test that useProgram applies the number of views in computing the final value of the attribute
1919// divisor.
1920TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1921{
1922 if (!requestMultiviewExtension())
1923 {
1924 return;
1925 }
1926
Geoff Lang25858162017-11-06 11:25:58 -05001927 // Test failing on P400 graphics card (anglebug.com/2228)
1928 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1929
Olli Etuaho44ae8992018-08-20 15:37:09 +03001930 // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
1931 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001932 if (IsWindows() && IsD3D11())
1933 {
1934 ignoreD3D11SDKLayersWarnings();
1935 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001936
Martin Radevced5c862017-08-17 16:05:29 +03001937 GLVertexArray vao;
1938 glBindVertexArray(vao);
1939 GLBuffer vbo;
1940 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1941 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
1942 Vector2I(3, 0)};
1943 std::vector<Vector2> vertexDataInClipSpace =
1944 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
1945 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
1946 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
1947 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1948 glEnableVertexAttribArray(0);
1949 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
1950 glVertexAttribDivisor(0, 1);
1951 ASSERT_GL_NO_ERROR();
1952
1953 // Create a program and fbo with N views and draw N instances of a point horizontally.
1954 for (int numViews = 2; numViews <= 4; ++numViews)
1955 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001956 updateFBOs(4, 1, numViews);
Martin Radevced5c862017-08-17 16:05:29 +03001957 ASSERT_GL_NO_ERROR();
1958
1959 GLuint program = CreateSimplePassthroughProgram(numViews);
1960 ASSERT_NE(program, 0u);
1961 glUseProgram(program);
1962 ASSERT_GL_NO_ERROR();
1963
1964 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
1965
1966 for (int view = 0; view < numViews; ++view)
1967 {
1968 for (int j = 0; j < numViews; ++j)
1969 {
Martin Radev67a8a012017-09-08 13:03:52 +03001970 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03001971 }
1972 for (int j = numViews; j < 4; ++j)
1973 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001974 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03001975 }
1976 }
1977
1978 glDeleteProgram(program);
1979 }
1980}
1981
Martin Radev72b4e1e2017-08-31 15:42:56 +03001982// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
1983TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
1984{
1985 if (!requestMultiviewExtension())
1986 {
1987 return;
1988 }
1989
1990 const std::string vsSource =
1991 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001992 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001993 "layout(num_views = 3) in;\n"
1994 "in vec3 vPosition;\n"
1995 "void main()\n"
1996 "{\n"
1997 " gl_Position = vec4(vPosition, 1.);\n"
1998 "}\n";
1999
2000 const std::string fsSource =
2001 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002002 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002003 "precision mediump float;\n"
2004 "out vec4 col;\n"
2005 "void main()\n"
2006 "{\n"
2007 " if (gl_ViewID_OVR == 0u) {\n"
2008 " col = vec4(1,0,0,1);\n"
2009 " } else if (gl_ViewID_OVR == 1u) {\n"
2010 " col = vec4(0,1,0,1);\n"
2011 " } else if (gl_ViewID_OVR == 2u) {\n"
2012 " col = vec4(0,0,1,1);\n"
2013 " } else {\n"
2014 " col = vec4(0,0,0,0);\n"
2015 " }\n"
2016 "}\n";
2017
Olli Etuaho4836acc2018-08-20 15:23:18 +03002018 updateFBOs(1, 1, 3);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002019 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002020
2021 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2022 ASSERT_GL_NO_ERROR();
2023
2024 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2025 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2026 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
2027}
2028
2029// The test checks that the inactive layers of a 2D texture array are not written to by a
2030// multi-view program.
2031TEST_P(MultiviewLayeredRenderTest, RenderToSubrageOfLayers)
2032{
2033 if (!requestMultiviewExtension())
2034 {
2035 return;
2036 }
2037
2038 const std::string vsSource =
2039 "#version 300 es\n"
2040 "#extension GL_OVR_multiview : require\n"
2041 "layout(num_views = 2) in;\n"
2042 "in vec3 vPosition;\n"
2043 "void main()\n"
2044 "{\n"
2045 " gl_Position = vec4(vPosition, 1.);\n"
2046 "}\n";
2047
2048 const std::string fsSource =
2049 "#version 300 es\n"
2050 "#extension GL_OVR_multiview : require\n"
2051 "precision mediump float;\n"
2052 "out vec4 col;\n"
2053 "void main()\n"
2054 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002055 " col = vec4(0,1,0,1);\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002056 "}\n";
2057
Olli Etuaho4836acc2018-08-20 15:23:18 +03002058 updateFBOs(1, 1, 2, 4, 1);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002059 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03002060
2061 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2062 ASSERT_GL_NO_ERROR();
2063
2064 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +03002065 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2066 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002067 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
2068}
2069
Martin Radevc1d4e552017-08-21 12:01:10 +03002070// The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
2071// potential bugs if the view is selected in the VS. The test contains a program in which the
2072// gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
2073// fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
2074// never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
2075// green for view 1.
2076TEST_P(MultiviewRenderTest, FlatInterpolation)
Martin Radev3c25ad02017-08-22 17:36:53 +03002077{
Martin Radevc1d4e552017-08-21 12:01:10 +03002078 if (!requestMultiviewExtension())
2079 {
2080 return;
2081 }
2082
2083 const std::string vsSource =
2084 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002085 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002086 "layout(num_views = 2) in;\n"
2087 "in vec3 vPosition;\n"
2088 "flat out int oInstanceID;\n"
2089 "void main()\n"
2090 "{\n"
2091 " gl_Position = vec4(vPosition, 1.);\n"
2092 " oInstanceID = gl_InstanceID;\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 Radevc1d4e552017-08-21 12:01:10 +03002098 "precision mediump float;\n"
2099 "flat in int oInstanceID;\n"
2100 "out vec4 col;\n"
2101 "void main()\n"
2102 "{\n"
2103 " if (oInstanceID < 0) {\n"
2104 " discard;\n"
2105 " }\n"
2106 " if (gl_ViewID_OVR == 0u) {\n"
2107 " col = vec4(1,0,0,1);\n"
2108 " } else {\n"
2109 " col = vec4(0,1,0,1);\n"
2110 " }\n"
2111 "}\n";
2112
Olli Etuaho4836acc2018-08-20 15:23:18 +03002113 updateFBOs(1, 1, 2);
Martin Radevc1d4e552017-08-21 12:01:10 +03002114 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2115
2116 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2117 ASSERT_GL_NO_ERROR();
2118
2119 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2120 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +03002121}
2122
Olli Etuaho604d8732018-07-20 11:02:43 +03002123// This test assigns gl_ViewID_OVR to a flat int varying and then sets the color based on that
2124// varying in the fragment shader.
2125TEST_P(MultiviewRenderTest, FlatInterpolation2)
2126{
2127 if (!requestMultiviewExtension())
2128 {
2129 return;
2130 }
2131
2132 const std::string vsSource =
2133 "#version 300 es\n"
2134 "#extension GL_OVR_multiview : require\n"
2135 "layout(num_views = 2) in;\n"
2136 "in vec3 vPosition;\n"
2137 "flat out int flatVarying;\n"
2138 "void main()\n"
2139 "{\n"
2140 " gl_Position = vec4(vPosition, 1.);\n"
2141 " flatVarying = int(gl_ViewID_OVR);\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 "flat in int flatVarying;\n"
2149 "out vec4 col;\n"
2150 "void main()\n"
2151 "{\n"
2152 " if (flatVarying == 0) {\n"
2153 " col = vec4(1,0,0,1);\n"
2154 " } else {\n"
2155 " col = vec4(0,1,0,1);\n"
2156 " }\n"
2157 "}\n";
2158
Olli Etuaho4836acc2018-08-20 15:23:18 +03002159 updateFBOs(1, 1, 2);
Olli Etuaho604d8732018-07-20 11:02:43 +03002160 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2161
2162 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2163 ASSERT_GL_NO_ERROR();
2164
2165 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2166 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2167}
2168
Martin Radev265a6d42017-09-12 16:51:37 +03002169// The test is added to cover a bug which resulted in the viewport/scissor and viewport offsets not
2170// being correctly applied.
2171TEST_P(MultiviewSideBySideRenderTest, ViewportOffsetsAppliedBugCoverage)
2172{
2173 if (!requestMultiviewExtension())
2174 {
2175 return;
2176 }
2177
Olli Etuaho4836acc2018-08-20 15:23:18 +03002178 updateFBOs(1, 1, 2);
Martin Radev265a6d42017-09-12 16:51:37 +03002179
2180 // Create multiview program.
2181 const std::string &vs =
2182 "#version 300 es\n"
2183 "#extension GL_OVR_multiview : require\n"
2184 "layout(num_views = 2) in;\n"
2185 "layout(location = 0) in vec3 vPosition;\n"
2186 "void main()\n"
2187 "{\n"
2188 " gl_Position = vec4(vPosition, 1.0);\n"
2189 "}\n";
2190
2191 const std::string &fs =
2192 "#version 300 es\n"
2193 "#extension GL_OVR_multiview : require\n"
2194 "precision mediump float;\n"
2195 "out vec4 col;\n"
2196 "void main()\n"
2197 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002198 " col = vec4(0,1,0,1);\n"
Martin Radev265a6d42017-09-12 16:51:37 +03002199 "}\n";
2200
2201 ANGLE_GL_PROGRAM(program, vs, fs);
2202
2203 glViewport(0, 0, 1, 1);
2204 glScissor(0, 0, 1, 1);
2205 glEnable(GL_SCISSOR_TEST);
2206 glClearColor(0, 0, 0, 1);
2207
2208 // Bind the default FBO and make sure that the state is synchronized.
2209 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
2210 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2211 ASSERT_GL_NO_ERROR();
2212
2213 // Draw and check that both views are rendered to.
Olli Etuaho4836acc2018-08-20 15:23:18 +03002214 bindMemberDrawFramebuffer();
Martin Radev265a6d42017-09-12 16:51:37 +03002215 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev67a8a012017-09-08 13:03:52 +03002216
Martin Radev265a6d42017-09-12 16:51:37 +03002217 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
Martin Radev67a8a012017-09-08 13:03:52 +03002218 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
2219 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev265a6d42017-09-12 16:51:37 +03002220}
2221
Olli Etuahof26b27e2018-08-17 11:01:19 +03002222MultiviewRenderTestParams SideBySideVertexShaderOpenGL(GLint majorVersion = 3,
2223 GLint minorVersion = 0)
Martin Radev3c25ad02017-08-22 17:36:53 +03002224{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002225 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE,
2226 VertexShaderOpenGL(majorVersion, minorVersion));
Martin Radev3c25ad02017-08-22 17:36:53 +03002227}
2228
Olli Etuahof26b27e2018-08-17 11:01:19 +03002229MultiviewRenderTestParams LayeredVertexShaderOpenGL()
Martin Radev3c25ad02017-08-22 17:36:53 +03002230{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002231 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
2232 VertexShaderOpenGL(3, 0));
Martin Radev3c25ad02017-08-22 17:36:53 +03002233}
2234
Olli Etuahof26b27e2018-08-17 11:01:19 +03002235MultiviewRenderTestParams SideBySideGeomShaderD3D11()
Martin Radev72b4e1e2017-08-31 15:42:56 +03002236{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002237 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE,
2238 GeomShaderD3D11(3, 0));
Martin Radevc1d4e552017-08-21 12:01:10 +03002239}
2240
Olli Etuahof26b27e2018-08-17 11:01:19 +03002241MultiviewRenderTestParams LayeredGeomShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002242{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002243 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, GeomShaderD3D11(3, 0));
Martin Radevc1d4e552017-08-21 12:01:10 +03002244}
2245
Olli Etuahof26b27e2018-08-17 11:01:19 +03002246MultiviewRenderTestParams SideBySideVertexShaderD3D11(GLint majorVersion = 3,
2247 GLint minorVersion = 0)
Martin Radevc1d4e552017-08-21 12:01:10 +03002248{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002249 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE,
2250 VertexShaderD3D11(majorVersion, minorVersion));
Martin Radevc1d4e552017-08-21 12:01:10 +03002251}
2252
Olli Etuahof26b27e2018-08-17 11:01:19 +03002253MultiviewRenderTestParams LayeredVertexShaderD3D11()
Martin Radevc1d4e552017-08-21 12:01:10 +03002254{
Olli Etuahof26b27e2018-08-17 11:01:19 +03002255 return MultiviewRenderTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
2256 VertexShaderD3D11(3, 0));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002257}
2258
Jamie Madill04c084d2018-08-08 15:49:28 -04002259ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest,
Olli Etuaho44ae8992018-08-20 15:37:09 +03002260 VertexShaderOpenGL(3, 1),
2261 VertexShaderD3D11(3, 1));
Martin Radevced5c862017-08-17 16:05:29 +03002262ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002263 SideBySideVertexShaderOpenGL(),
2264 LayeredVertexShaderOpenGL(),
2265 SideBySideGeomShaderD3D11(),
2266 SideBySideVertexShaderD3D11(),
2267 LayeredGeomShaderD3D11(),
2268 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002269ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002270 SideBySideVertexShaderOpenGL(),
2271 LayeredVertexShaderOpenGL(),
2272 SideBySideGeomShaderD3D11(),
2273 SideBySideVertexShaderD3D11(),
2274 LayeredGeomShaderD3D11(),
2275 LayeredVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002276ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002277 SideBySideVertexShaderOpenGL(),
2278 LayeredVertexShaderOpenGL(),
2279 SideBySideGeomShaderD3D11(),
2280 SideBySideVertexShaderD3D11(),
2281 LayeredGeomShaderD3D11(),
2282 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002283ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
Olli Etuaho4bcaf992018-08-17 17:18:28 +03002284 VertexShaderOpenGL(3, 0),
2285 GeomShaderD3D11(3, 0),
2286 VertexShaderD3D11(3, 0));
Martin Radevced5c862017-08-17 16:05:29 +03002287ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002288 SideBySideVertexShaderOpenGL(),
2289 LayeredVertexShaderOpenGL(),
2290 SideBySideGeomShaderD3D11(),
2291 SideBySideVertexShaderD3D11(),
2292 LayeredGeomShaderD3D11(),
2293 LayeredVertexShaderD3D11());
Jamie Madill04c084d2018-08-08 15:49:28 -04002294ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest,
2295 VertexShaderOpenGL(3, 0),
2296 GeomShaderD3D11(3, 0));
2297ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, VertexShaderOpenGL(3, 0), GeomShaderD3D11(3, 0));