blob: ce3400bb189febe89a5523aa53a35ca4f231df8c [file] [log] [blame]
Martin Radev14a26ae2017-07-24 15:56:29 +03001//
2// Copyright 2017 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6// Multiview draw tests:
7// Test issuing multiview Draw* commands.
8//
9
Martin Radevc1d4e552017-08-21 12:01:10 +030010#include "platform/WorkaroundsD3D.h"
Olli Etuahof26b27e2018-08-17 11:01:19 +030011#include "test_utils/MultiviewTest.h"
Martin Radev14a26ae2017-07-24 15:56:29 +030012#include "test_utils/gl_raii.h"
13
14using namespace angle;
15
Martin Radev61bd9992017-08-11 13:10:55 +030016namespace
17{
Martin Radev61bd9992017-08-11 13:10:55 +030018
19std::vector<Vector2> ConvertPixelCoordinatesToClipSpace(const std::vector<Vector2I> &pixels,
20 int width,
21 int height)
22{
23 std::vector<Vector2> result(pixels.size());
24 for (size_t i = 0; i < pixels.size(); ++i)
25 {
26 const auto &pixel = pixels[i];
27 float pixelCenterRelativeX = (static_cast<float>(pixel.x()) + .5f) / width;
28 float pixelCenterRelativeY = (static_cast<float>(pixel.y()) + .5f) / height;
29 float xInClipSpace = 2.f * pixelCenterRelativeX - 1.f;
30 float yInClipSpace = 2.f * pixelCenterRelativeY - 1.f;
31 result[i] = Vector2(xInClipSpace, yInClipSpace);
32 }
33 return result;
34}
35} // namespace
36
Olli Etuahof26b27e2018-08-17 11:01:19 +030037struct MultiviewRenderTestParams final : public MultiviewImplementationParams
Martin Radev3c25ad02017-08-22 17:36:53 +030038{
Mingyu Hu7d64c482019-03-12 14:27:40 -070039 MultiviewRenderTestParams(int samples,
Olli Etuahof26b27e2018-08-17 11:01:19 +030040 const MultiviewImplementationParams &implementationParams)
Mingyu Hu7d64c482019-03-12 14:27:40 -070041 : MultiviewImplementationParams(implementationParams), mSamples(samples)
42 {}
Olli Etuaho2c8f0842018-09-12 14:44:55 +030043 int mSamples;
Martin Radev3c25ad02017-08-22 17:36:53 +030044};
45
Olli Etuahof26b27e2018-08-17 11:01:19 +030046std::ostream &operator<<(std::ostream &os, const MultiviewRenderTestParams &params)
Martin Radev3c25ad02017-08-22 17:36:53 +030047{
Martin Radevc1d4e552017-08-21 12:01:10 +030048 const MultiviewImplementationParams &base =
49 static_cast<const MultiviewImplementationParams &>(params);
Martin Radev3c25ad02017-08-22 17:36:53 +030050 os << base;
Mingyu Hu7d64c482019-03-12 14:27:40 -070051 os << "_layered";
52
Olli Etuaho2c8f0842018-09-12 14:44:55 +030053 if (params.mSamples > 0)
54 {
55 os << "_samples_" << params.mSamples;
56 }
Martin Radev3c25ad02017-08-22 17:36:53 +030057 return os;
58}
59
Mingyu Huebab6702019-04-19 14:36:45 -070060class MultiviewFramebufferTestBase : public MultiviewTestBase,
61 public ::testing::TestWithParam<MultiviewRenderTestParams>
Martin Radev8f276e22017-05-30 12:05:52 +030062{
63 protected:
Mingyu Hu7d64c482019-03-12 14:27:40 -070064 MultiviewFramebufferTestBase(const PlatformParameters &params, int samples)
Olli Etuahof26b27e2018-08-17 11:01:19 +030065 : MultiviewTestBase(params),
Martin Radev3c25ad02017-08-22 17:36:53 +030066 mViewWidth(0),
67 mViewHeight(0),
Olli Etuaho4836acc2018-08-20 15:23:18 +030068 mNumViews(0),
Olli Etuaho44ae8992018-08-20 15:37:09 +030069 mColorTexture(0u),
70 mDepthTexture(0u),
71 mDrawFramebuffer(0u),
Olli Etuaho2c8f0842018-09-12 14:44:55 +030072 mSamples(samples),
73 mResolveTexture(0u)
Jamie Madillb980c562018-11-27 11:34:27 -050074 {}
Olli Etuaho44ae8992018-08-20 15:37:09 +030075
Olli Etuaho4836acc2018-08-20 15:23:18 +030076 void FramebufferTestSetUp() { MultiviewTestBase::MultiviewTestBaseSetUp(); }
Olli Etuaho44ae8992018-08-20 15:37:09 +030077
78 void FramebufferTestTearDown()
79 {
80 freeFBOs();
81 MultiviewTestBase::MultiviewTestBaseTearDown();
82 }
83
Olli Etuaho4836acc2018-08-20 15:23:18 +030084 void updateFBOs(int viewWidth, int height, int numViews, int numLayers, int baseViewIndex)
Martin Radev3c25ad02017-08-22 17:36:53 +030085 {
Jamie Madillba319ba2018-12-29 10:29:33 -050086 ASSERT_TRUE(numViews + baseViewIndex <= numLayers);
Martin Radev72b4e1e2017-08-31 15:42:56 +030087
Olli Etuaho44ae8992018-08-20 15:37:09 +030088 freeFBOs();
89
Martin Radev3c25ad02017-08-22 17:36:53 +030090 mViewWidth = viewWidth;
91 mViewHeight = height;
92 mNumViews = numViews;
Martin Radev8f276e22017-05-30 12:05:52 +030093
Olli Etuaho44ae8992018-08-20 15:37:09 +030094 glGenTextures(1, &mColorTexture);
95 glGenTextures(1, &mDepthTexture);
Martin Radev0abb7a22017-08-28 15:34:45 +030096
Mingyu Hu7d64c482019-03-12 14:27:40 -070097 CreateMultiviewBackingTextures(mSamples, viewWidth, height, numLayers, mColorTexture,
98 mDepthTexture, 0u);
Martin Radev3c25ad02017-08-22 17:36:53 +030099
Olli Etuaho44ae8992018-08-20 15:37:09 +0300100 glGenFramebuffers(1, &mDrawFramebuffer);
101
Martin Radev3c25ad02017-08-22 17:36:53 +0300102 // Create draw framebuffer to be used for multiview rendering.
103 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700104 AttachMultiviewTextures(GL_DRAW_FRAMEBUFFER, viewWidth, numViews, baseViewIndex,
105 mColorTexture, mDepthTexture, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300106
Martin Radev8f276e22017-05-30 12:05:52 +0300107 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
108
109 // Create read framebuffer to be used to retrieve the pixel information for testing
110 // purposes.
Mingyu Hu7d64c482019-03-12 14:27:40 -0700111 mReadFramebuffer.resize(numLayers);
112 glGenFramebuffers(static_cast<GLsizei>(mReadFramebuffer.size()), mReadFramebuffer.data());
113 for (int i = 0; i < numLayers; ++i)
Martin Radev3c25ad02017-08-22 17:36:53 +0300114 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700115 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
116 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mColorTexture, 0,
117 i);
118 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
119 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300120 }
Martin Radev8f276e22017-05-30 12:05:52 +0300121
122 // Clear the buffers.
Martin Radev3c25ad02017-08-22 17:36:53 +0300123 glViewport(0, 0, viewWidth, height);
Martin Radev3c25ad02017-08-22 17:36:53 +0300124 }
Martin Radev8f276e22017-05-30 12:05:52 +0300125
Olli Etuaho4836acc2018-08-20 15:23:18 +0300126 void updateFBOs(int viewWidth, int height, int numViews)
Martin Radev72b4e1e2017-08-31 15:42:56 +0300127 {
Olli Etuaho4836acc2018-08-20 15:23:18 +0300128 updateFBOs(viewWidth, height, numViews, numViews, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300129 }
130
Olli Etuaho4836acc2018-08-20 15:23:18 +0300131 void bindMemberDrawFramebuffer() { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer); }
132
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300133 // In case we have a multisampled framebuffer, creates and binds a resolve framebuffer as the
134 // draw framebuffer, and resolves the read framebuffer to it.
135 void resolveMultisampledFBO()
136 {
137 if (mSamples == 0)
138 {
139 return;
140 }
141 int numLayers = mReadFramebuffer.size();
142 if (mResolveFramebuffer.empty())
143 {
Jamie Madillba319ba2018-12-29 10:29:33 -0500144 ASSERT_TRUE(mResolveTexture == 0u);
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300145 glGenTextures(1, &mResolveTexture);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700146 CreateMultiviewBackingTextures(0, mViewWidth, mViewHeight, numLayers, mResolveTexture,
147 0u, 0u);
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300148
149 mResolveFramebuffer.resize(numLayers);
150 glGenFramebuffers(static_cast<GLsizei>(mResolveFramebuffer.size()),
151 mResolveFramebuffer.data());
152 for (int i = 0; i < numLayers; ++i)
153 {
154 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFramebuffer[i]);
155 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
156 mResolveTexture, 0, i);
157 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
158 glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
159 }
160 }
161 for (int i = 0; i < numLayers; ++i)
162 {
163 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
164 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFramebuffer[i]);
165 glBlitFramebuffer(0, 0, mViewWidth, mViewHeight, 0, 0, mViewWidth, mViewHeight,
166 GL_COLOR_BUFFER_BIT, GL_NEAREST);
167 }
168 }
169
Martin Radev3c25ad02017-08-22 17:36:53 +0300170 GLColor GetViewColor(int x, int y, int view)
171 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700172 EXPECT_TRUE(static_cast<size_t>(view) < mReadFramebuffer.size());
173 if (mSamples > 0)
Martin Radev3c25ad02017-08-22 17:36:53 +0300174 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700175 EXPECT_TRUE(static_cast<size_t>(view) < mResolveFramebuffer.size());
176 glBindFramebuffer(GL_READ_FRAMEBUFFER, mResolveFramebuffer[view]);
Martin Radev3c25ad02017-08-22 17:36:53 +0300177 }
Mingyu Hu7d64c482019-03-12 14:27:40 -0700178 else
179 {
180 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
181 }
182 return ReadColor(x, y);
Martin Radev8f276e22017-05-30 12:05:52 +0300183 }
184
Mingyu Huebab6702019-04-19 14:36:45 -0700185 // Requests the OVR_multiview(2) extension and returns true if the operation succeeds.
186 bool requestMultiviewExtension(bool requireMultiviewMultisample)
187 {
188 if (!EnsureGLExtensionEnabled(extensionName()))
189 {
190 std::cout << "Test skipped due to missing " << extensionName() << "." << std::endl;
191 return false;
192 }
193
194 if (requireMultiviewMultisample)
195 {
196 if (!EnsureGLExtensionEnabled("GL_OES_texture_storage_multisample_2d_array"))
197 {
198 std::cout << "Test skipped due to missing GL_ANGLE_multiview_multisample."
199 << std::endl;
200 return false;
201 }
202
203 if (!EnsureGLExtensionEnabled("GL_ANGLE_multiview_multisample"))
204 {
205 std::cout << "Test skipped due to missing GL_ANGLE_multiview_multisample."
206 << std::endl;
207 return false;
208 }
209 }
210 return true;
211 }
212
213 bool requestMultiviewExtension() { return requestMultiviewExtension(false); }
214 std::string extensionName()
215 {
216 switch (GetParam().mMultiviewExtension)
217 {
218 case multiview:
219 return "GL_OVR_multiview";
220 case multiview2:
221 return "GL_OVR_multiview2";
222 default:
223 // Ignore unknown.
224 return "";
225 }
226 }
227
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300228 bool isMultisampled() { return mSamples > 0; }
229
Martin Radev3c25ad02017-08-22 17:36:53 +0300230 int mViewWidth;
231 int mViewHeight;
232 int mNumViews;
Olli Etuaho4836acc2018-08-20 15:23:18 +0300233
Olli Etuaho44ae8992018-08-20 15:37:09 +0300234 GLuint mColorTexture;
235 GLuint mDepthTexture;
236
Olli Etuaho4836acc2018-08-20 15:23:18 +0300237 private:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300238 GLuint mDrawFramebuffer;
239 std::vector<GLuint> mReadFramebuffer;
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300240 int mSamples;
241
242 // For reading back multisampled framebuffer.
243 std::vector<GLuint> mResolveFramebuffer;
244 GLuint mResolveTexture;
Olli Etuaho44ae8992018-08-20 15:37:09 +0300245
246 void freeFBOs()
247 {
248 if (mDrawFramebuffer)
249 {
250 glDeleteFramebuffers(1, &mDrawFramebuffer);
251 mDrawFramebuffer = 0;
252 }
253 if (!mReadFramebuffer.empty())
254 {
Shahbaz Youssefic4097442018-08-22 12:14:52 -0400255 GLsizei framebufferCount = static_cast<GLsizei>(mReadFramebuffer.size());
256 glDeleteFramebuffers(framebufferCount, mReadFramebuffer.data());
Olli Etuaho44ae8992018-08-20 15:37:09 +0300257 mReadFramebuffer.clear();
258 }
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300259 if (!mResolveFramebuffer.empty())
260 {
261 GLsizei framebufferCount = static_cast<GLsizei>(mResolveFramebuffer.size());
262 glDeleteFramebuffers(framebufferCount, mResolveFramebuffer.data());
263 mResolveFramebuffer.clear();
264 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300265 if (mDepthTexture)
266 {
267 glDeleteTextures(1, &mDepthTexture);
268 mDepthTexture = 0;
269 }
270 if (mColorTexture)
271 {
272 glDeleteTextures(1, &mColorTexture);
273 mColorTexture = 0;
274 }
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300275 if (mResolveTexture)
276 {
277 glDeleteTextures(1, &mResolveTexture);
278 mResolveTexture = 0;
279 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300280 }
Martin Radev8f276e22017-05-30 12:05:52 +0300281};
282
Mingyu Huebab6702019-04-19 14:36:45 -0700283class MultiviewRenderTest : public MultiviewFramebufferTestBase
Martin Radev8f276e22017-05-30 12:05:52 +0300284{
285 protected:
Mingyu Hu7d64c482019-03-12 14:27:40 -0700286 MultiviewRenderTest() : MultiviewFramebufferTestBase(GetParam(), GetParam().mSamples) {}
Martin Radevc1d4e552017-08-21 12:01:10 +0300287
288 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
289 {
290 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
291 }
Jamie Madill5cbaa3f2019-05-07 15:49:22 -0400292
293 virtual void testSetUp() {}
294 virtual void testTearDown() {}
295
296 private:
297 void SetUp() override
298 {
299 MultiviewFramebufferTestBase::FramebufferTestSetUp();
300 testSetUp();
301 }
302 void TearDown() override
303 {
304 testTearDown();
305 MultiviewFramebufferTestBase::FramebufferTestTearDown();
306 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300307};
308
Mingyu Huebab6702019-04-19 14:36:45 -0700309std::string DualViewVS(ExtensionName multiviewExtension)
Jamie Madill04c084d2018-08-08 15:49:28 -0400310{
Mingyu Huebab6702019-04-19 14:36:45 -0700311 std::string ext;
312 switch (multiviewExtension)
313 {
314 case multiview:
315 ext = "GL_OVR_multiview";
316 break;
317 case multiview2:
318 ext = "GL_OVR_multiview2";
319 break;
320 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400321
Mingyu Huebab6702019-04-19 14:36:45 -0700322 std::string dualViewVSSource =
323 "#version 300 es\n"
324 "#extension " +
325 ext +
326 " : require\n"
327 "layout(num_views = 2) in;\n"
328 "in vec4 vPosition;\n"
329 "void main()\n"
330 "{\n"
331 " gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x * 0.5 + 0.5 : vPosition.x * 0.5 - "
332 "0.5);\n"
333 " gl_Position.yzw = vPosition.yzw;\n"
334 "}\n";
335 return dualViewVSSource;
336}
337
338std::string DualViewFS(ExtensionName multiviewExtension)
Jamie Madill04c084d2018-08-08 15:49:28 -0400339{
Mingyu Huebab6702019-04-19 14:36:45 -0700340 std::string ext;
341 switch (multiviewExtension)
342 {
343 case multiview:
344 ext = "GL_OVR_multiview";
345 break;
346 case multiview2:
347 ext = "GL_OVR_multiview2";
348 break;
349 }
350
351 std::string dualViewFSSource =
352 "#version 300 es\n"
353 "#extension " +
354 ext +
355 " : require\n"
356 "precision mediump float;\n"
357 "out vec4 col;\n"
358 "void main()\n"
359 "{\n"
360 " col = vec4(0,1,0,1);\n"
361 "}\n";
362 return dualViewFSSource;
363}
Jamie Madill04c084d2018-08-08 15:49:28 -0400364
Martin Radev3c25ad02017-08-22 17:36:53 +0300365class MultiviewRenderDualViewTest : public MultiviewRenderTest
366{
367 protected:
368 MultiviewRenderDualViewTest() : mProgram(0u) {}
Martin Radev8f276e22017-05-30 12:05:52 +0300369
Jamie Madill5cbaa3f2019-05-07 15:49:22 -0400370 void testSetUp() override
Martin Radev8f276e22017-05-30 12:05:52 +0300371 {
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300372 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev8f276e22017-05-30 12:05:52 +0300373 {
374 return;
375 }
376
Olli Etuaho4836acc2018-08-20 15:23:18 +0300377 updateFBOs(2, 1, 2);
Mingyu Huebab6702019-04-19 14:36:45 -0700378 mProgram = CompileProgram(DualViewVS(GetParam().mMultiviewExtension).c_str(),
379 DualViewFS(GetParam().mMultiviewExtension).c_str());
Martin Radev61bd9992017-08-11 13:10:55 +0300380 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300381 glUseProgram(mProgram);
382 ASSERT_GL_NO_ERROR();
383 }
384
Jamie Madill5cbaa3f2019-05-07 15:49:22 -0400385 void testTearDown() override
Olli Etuaho44ae8992018-08-20 15:37:09 +0300386 {
387 if (mProgram != 0u)
388 {
389 glDeleteProgram(mProgram);
390 mProgram = 0u;
391 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300392 }
393
Martin Radev8f276e22017-05-30 12:05:52 +0300394 void checkOutput()
395 {
Olli Etuaho2c8f0842018-09-12 14:44:55 +0300396 resolveMultisampledFBO();
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300397 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +0300398 EXPECT_EQ(GLColor::green, GetViewColor(1, 0, 0));
399 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300400 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(1, 0, 1));
Martin Radev8f276e22017-05-30 12:05:52 +0300401 }
402
403 GLuint mProgram;
404};
405
Olli Etuaho44ae8992018-08-20 15:37:09 +0300406// Base class for tests that care mostly about draw call validity and not rendering results.
407class MultiviewDrawValidationTest : public MultiviewTest
Jamie Madill04c084d2018-08-08 15:49:28 -0400408{
409 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300410 MultiviewDrawValidationTest() : MultiviewTest() {}
Jamie Madill04c084d2018-08-08 15:49:28 -0400411
Mingyu Hu7d64c482019-03-12 14:27:40 -0700412 void initOnePixelColorTexture2DSingleLayered(GLuint texId)
Jamie Madill04c084d2018-08-08 15:49:28 -0400413 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700414 glBindTexture(GL_TEXTURE_2D_ARRAY, texId);
415 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
416 nullptr);
417 }
418
419 void initOnePixelColorTexture2DMultiLayered(GLuint texId)
420 {
421 glBindTexture(GL_TEXTURE_2D_ARRAY, texId);
422 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
423 nullptr);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300424 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400425
Olli Etuaho44ae8992018-08-20 15:37:09 +0300426 // This initializes a simple VAO with a valid vertex buffer and index buffer with three
427 // vertices.
428 void initVAO(GLuint vao, GLuint vertexBuffer, GLuint indexBuffer)
429 {
430 glBindVertexArray(vao);
Jamie Madill04c084d2018-08-08 15:49:28 -0400431
432 const float kVertexData[3] = {0.0f};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300433 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400434 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
435
436 const unsigned int kIndices[3] = {0u, 1u, 2u};
Olli Etuaho44ae8992018-08-20 15:37:09 +0300437 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
Jamie Madill04c084d2018-08-08 15:49:28 -0400438 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
439 GL_STATIC_DRAW);
440 ASSERT_GL_NO_ERROR();
441 }
Jamie Madill04c084d2018-08-08 15:49:28 -0400442};
443
Martin Radev3c25ad02017-08-22 17:36:53 +0300444class MultiviewOcclusionQueryTest : public MultiviewRenderTest
Martin Radev0d671c92017-08-10 16:41:52 +0300445{
446 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300447 MultiviewOcclusionQueryTest() {}
Martin Radev0d671c92017-08-10 16:41:52 +0300448
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400449 bool requestOcclusionQueryExtension()
450 {
Mingyu Huebab6702019-04-19 14:36:45 -0700451 if (!EnsureGLExtensionEnabled("GL_EXT_occlusion_query_boolean"))
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400452 {
453 std::cout << "Test skipped due to missing GL_EXT_occlusion_query_boolean." << std::endl;
454 return false;
455 }
456 return true;
457 }
458
Martin Radev0d671c92017-08-10 16:41:52 +0300459 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
460 {
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400461 GLQueryEXT query;
462 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED, query);
Martin Radev0d671c92017-08-10 16:41:52 +0300463 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
464 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
465
466 GLuint result = GL_TRUE;
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400467 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT, &result);
Martin Radev0d671c92017-08-10 16:41:52 +0300468 return result;
469 }
470};
471
Olli Etuaho4bcaf992018-08-17 17:18:28 +0300472class MultiviewProgramGenerationTest : public MultiviewTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300473{
474 protected:
475 MultiviewProgramGenerationTest() {}
476};
477
Martin Radev3c25ad02017-08-22 17:36:53 +0300478class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300479{
480 protected:
Olli Etuaho44ae8992018-08-20 15:37:09 +0300481 MultiviewRenderPrimitiveTest() : mVBO(0u) {}
482
Jamie Madill5cbaa3f2019-05-07 15:49:22 -0400483 void testSetUp() override { glGenBuffers(1, &mVBO); }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300484
Jamie Madill5cbaa3f2019-05-07 15:49:22 -0400485 void testTearDown() override
Olli Etuaho44ae8992018-08-20 15:37:09 +0300486 {
487 if (mVBO)
488 {
489 glDeleteBuffers(1, &mVBO);
490 mVBO = 0u;
491 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300492 }
Martin Radev61bd9992017-08-11 13:10:55 +0300493
494 void setupGeometry(const std::vector<Vector2> &vertexData)
495 {
Martin Radev61bd9992017-08-11 13:10:55 +0300496 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
497 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
498 GL_STATIC_DRAW);
499 glEnableVertexAttribArray(0);
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500500 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
Martin Radev61bd9992017-08-11 13:10:55 +0300501 }
502
Martin Radev67a8a012017-09-08 13:03:52 +0300503 void checkGreenChannel(const GLubyte expectedGreenChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300504 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300505 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300506 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300507 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300508 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300509 for (int h = 0; h < mViewHeight; ++h)
510 {
511 size_t flatIndex =
512 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
Olli Etuahoa7b35c32018-08-21 16:32:24 +0300513 EXPECT_EQ(GLColor(0, expectedGreenChannelData[flatIndex], 0,
514 expectedGreenChannelData[flatIndex]),
Martin Radev3c25ad02017-08-22 17:36:53 +0300515 GetViewColor(w, h, view));
516 }
Martin Radev61bd9992017-08-11 13:10:55 +0300517 }
518 }
519 }
Olli Etuaho44ae8992018-08-20 15:37:09 +0300520 GLuint mVBO;
Martin Radev61bd9992017-08-11 13:10:55 +0300521};
522
Mingyu Huebab6702019-04-19 14:36:45 -0700523class MultiviewLayeredRenderTest : public MultiviewFramebufferTestBase
Martin Radev72b4e1e2017-08-31 15:42:56 +0300524{
525 protected:
Mingyu Hu7d64c482019-03-12 14:27:40 -0700526 MultiviewLayeredRenderTest() : MultiviewFramebufferTestBase(GetParam(), 0) {}
Olli Etuaho44ae8992018-08-20 15:37:09 +0300527 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
528 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
529 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
Martin Radevc1d4e552017-08-21 12:01:10 +0300530 {
531 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
532 }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300533};
534
Mingyu Hu7d64c482019-03-12 14:27:40 -0700535// The test verifies that glDraw*Indirect works for any number of views.
Martin Radev7cf61662017-07-26 17:10:53 +0300536TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300537{
Jamie Madill3a256222018-12-08 09:56:39 -0500538 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radev14a26ae2017-07-24 15:56:29 +0300539
Mingyu Huebab6702019-04-19 14:36:45 -0700540 const std::string FS =
Martin Radev14a26ae2017-07-24 15:56:29 +0300541 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -0700542 "#extension " +
543 extensionName() +
544 ": require\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300545 "precision mediump float;\n"
shrekshao15ce8222019-03-18 19:25:21 -0700546 "out vec4 color;\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300547 "void main()\n"
shrekshao15ce8222019-03-18 19:25:21 -0700548 "{color = vec4(1);}\n";
Martin Radev14a26ae2017-07-24 15:56:29 +0300549
Olli Etuaho44ae8992018-08-20 15:37:09 +0300550 GLVertexArray vao;
551 GLBuffer vertexBuffer;
552 GLBuffer indexBuffer;
553 initVAO(vao, vertexBuffer, indexBuffer);
554
555 GLFramebuffer fbo;
556 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
557
Martin Radev14a26ae2017-07-24 15:56:29 +0300558 GLBuffer commandBuffer;
559 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
560 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
561 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
562 ASSERT_GL_NO_ERROR();
563
Mingyu Hu7d64c482019-03-12 14:27:40 -0700564 // Check that no errors are generated with the framebuffer having 2 views.
Martin Radev14a26ae2017-07-24 15:56:29 +0300565 {
Mingyu Huebab6702019-04-19 14:36:45 -0700566 const std::string VS =
Martin Radev14a26ae2017-07-24 15:56:29 +0300567 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -0700568 "#extension " +
569 extensionName() +
570 ": require\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300571 "layout(num_views = 2) in;\n"
572 "void main()\n"
573 "{}\n";
Mingyu Huebab6702019-04-19 14:36:45 -0700574 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radev14a26ae2017-07-24 15:56:29 +0300575 glUseProgram(program);
576
Mingyu Hu7d64c482019-03-12 14:27:40 -0700577 GLTexture tex2DArray;
578 initOnePixelColorTexture2DMultiLayered(tex2DArray);
579
580 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radev14a26ae2017-07-24 15:56:29 +0300581
582 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700583 EXPECT_GL_NO_ERROR();
Martin Radev14a26ae2017-07-24 15:56:29 +0300584
585 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700586 EXPECT_GL_NO_ERROR();
Martin Radev14a26ae2017-07-24 15:56:29 +0300587 }
588
589 // Check that no errors are generated if the number of views is 1.
590 {
Mingyu Huebab6702019-04-19 14:36:45 -0700591 const std::string VS =
Martin Radev14a26ae2017-07-24 15:56:29 +0300592 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -0700593 "#extension " +
594 extensionName() +
595 ": require\n"
Martin Radev14a26ae2017-07-24 15:56:29 +0300596 "layout(num_views = 1) in;\n"
597 "void main()\n"
598 "{}\n";
Mingyu Huebab6702019-04-19 14:36:45 -0700599 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radev14a26ae2017-07-24 15:56:29 +0300600 glUseProgram(program);
601
Mingyu Hu7d64c482019-03-12 14:27:40 -0700602 GLTexture tex2D;
603 initOnePixelColorTexture2DSingleLayered(tex2D);
604
605 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Martin Radev14a26ae2017-07-24 15:56:29 +0300606
607 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
608 EXPECT_GL_NO_ERROR();
609
610 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
611 EXPECT_GL_NO_ERROR();
612 }
613}
614
Martin Radev7cf61662017-07-26 17:10:53 +0300615// The test verifies that glDraw*:
616// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
617// program differs.
618// 2) does not generate any error if the number of views is the same.
Martin Radev7cf61662017-07-26 17:10:53 +0300619TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
620{
Jamie Madill3a256222018-12-08 09:56:39 -0500621 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radev7cf61662017-07-26 17:10:53 +0300622
Mingyu Huebab6702019-04-19 14:36:45 -0700623 const std::string VS =
Martin Radev7cf61662017-07-26 17:10:53 +0300624 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -0700625 "#extension " +
626 extensionName() +
627 ": require\n"
Martin Radev7cf61662017-07-26 17:10:53 +0300628 "layout(num_views = 2) in;\n"
629 "void main()\n"
630 "{}\n";
Mingyu Huebab6702019-04-19 14:36:45 -0700631 const std::string FS =
Martin Radev7cf61662017-07-26 17:10:53 +0300632 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -0700633 "#extension " +
634 extensionName() +
635 ": require\n"
Martin Radev7cf61662017-07-26 17:10:53 +0300636 "precision mediump float;\n"
shrekshao15ce8222019-03-18 19:25:21 -0700637 "out vec4 color;\n"
Martin Radev7cf61662017-07-26 17:10:53 +0300638 "void main()\n"
shrekshao15ce8222019-03-18 19:25:21 -0700639 "{color = vec4(1);}\n";
Mingyu Huebab6702019-04-19 14:36:45 -0700640 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radev7cf61662017-07-26 17:10:53 +0300641 glUseProgram(program);
642
Olli Etuaho44ae8992018-08-20 15:37:09 +0300643 GLVertexArray vao;
644 GLBuffer vertexBuffer;
645 GLBuffer indexBuffer;
646 initVAO(vao, vertexBuffer, indexBuffer);
647
648 GLFramebuffer fbo;
649 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
650
Martin Radev7cf61662017-07-26 17:10:53 +0300651 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
652 // number of views.
653 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700654 GLTexture tex2D;
655 initOnePixelColorTexture2DSingleLayered(tex2D);
656
Martin Radev7cf61662017-07-26 17:10:53 +0300657 // The framebuffer has only 1 view.
Mingyu Hu7d64c482019-03-12 14:27:40 -0700658 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Martin Radev7cf61662017-07-26 17:10:53 +0300659
660 glDrawArrays(GL_TRIANGLES, 0, 3);
661 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
662
663 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
664 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
665 }
666
667 // Check that no errors are generated if the number of views in both program and draw
668 // framebuffer matches.
669 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700670 GLTexture tex2DArray;
671 initOnePixelColorTexture2DMultiLayered(tex2DArray);
672
673 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radev7cf61662017-07-26 17:10:53 +0300674
675 glDrawArrays(GL_TRIANGLES, 0, 3);
676 EXPECT_GL_NO_ERROR();
677
678 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
679 EXPECT_GL_NO_ERROR();
680 }
Martin Radevda8e2572017-09-12 17:21:16 +0300681}
Martin Radev7cf61662017-07-26 17:10:53 +0300682
Martin Radevda8e2572017-09-12 17:21:16 +0300683// The test verifies that glDraw* generates an INVALID_OPERATION error if the program does not use
684// the multiview extension, but the active draw framebuffer has more than one view.
685TEST_P(MultiviewDrawValidationTest, NumViewsMismatchForNonMultiviewProgram)
686{
687 if (!requestMultiviewExtension())
Martin Radev7cf61662017-07-26 17:10:53 +0300688 {
Martin Radevda8e2572017-09-12 17:21:16 +0300689 return;
Martin Radev7cf61662017-07-26 17:10:53 +0300690 }
Martin Radevda8e2572017-09-12 17:21:16 +0300691
Jamie Madill35cd7332018-12-02 12:03:33 -0500692 constexpr char kVS[] =
Martin Radevda8e2572017-09-12 17:21:16 +0300693 "#version 300 es\n"
694 "void main()\n"
695 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500696 constexpr char kFS[] =
Martin Radevda8e2572017-09-12 17:21:16 +0300697 "#version 300 es\n"
698 "precision mediump float;\n"
699 "void main()\n"
700 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500701 ANGLE_GL_PROGRAM(programNoMultiview, kVS, kFS);
Martin Radevda8e2572017-09-12 17:21:16 +0300702 glUseProgram(programNoMultiview);
703
Olli Etuaho44ae8992018-08-20 15:37:09 +0300704 GLVertexArray vao;
705 GLBuffer vertexBuffer;
706 GLBuffer indexBuffer;
707 initVAO(vao, vertexBuffer, indexBuffer);
708
709 GLFramebuffer fbo;
710 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
711
Mingyu Hu7d64c482019-03-12 14:27:40 -0700712 GLTexture tex2DArray;
713 initOnePixelColorTexture2DMultiLayered(tex2DArray);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300714
Mingyu Hu7d64c482019-03-12 14:27:40 -0700715 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radevda8e2572017-09-12 17:21:16 +0300716
717 glDrawArrays(GL_TRIANGLES, 0, 3);
718 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
719
720 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
721 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radev7cf61662017-07-26 17:10:53 +0300722}
723
Martin Radev7e69f762017-07-27 14:54:13 +0300724// The test verifies that glDraw*:
725// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
Jamie Madill3a256222018-12-08 09:56:39 -0500726// greater than 1 and there is an active not paused transform feedback object.
Martin Radev7e69f762017-07-27 14:54:13 +0300727// 2) does not generate any error if the number of views in the draw framebuffer is 1.
728TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
729{
Jamie Madill3a256222018-12-08 09:56:39 -0500730 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Martin Radev7e69f762017-07-27 14:54:13 +0300731
Jamie Madill35cd7332018-12-02 12:03:33 -0500732 constexpr char kVS[] = R"(#version 300 es
733out float tfVarying;
734void main()
735{
736 tfVarying = 1.0;
737})";
738
739 constexpr char kFS[] = R"(#version 300 es
740precision mediump float;
741void main()
742{})";
Jamie Madill04c084d2018-08-08 15:49:28 -0400743
Olli Etuaho3755c482017-10-13 15:40:26 +0300744 std::vector<std::string> tfVaryings;
Jamie Madill04c084d2018-08-08 15:49:28 -0400745 tfVaryings.emplace_back("tfVarying");
Jamie Madill35cd7332018-12-02 12:03:33 -0500746 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(singleViewProgram, kVS, kFS, tfVaryings,
Olli Etuaho3755c482017-10-13 15:40:26 +0300747 GL_SEPARATE_ATTRIBS);
Jamie Madill04c084d2018-08-08 15:49:28 -0400748
749 std::vector<std::string> dualViewTFVaryings;
750 dualViewTFVaryings.emplace_back("gl_Position");
Mingyu Huebab6702019-04-19 14:36:45 -0700751 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(dualViewProgram,
752 DualViewVS(GetParam().mMultiviewExtension).c_str(),
753 DualViewFS(GetParam().mMultiviewExtension).c_str(),
Jamie Madill04c084d2018-08-08 15:49:28 -0400754 dualViewTFVaryings, GL_SEPARATE_ATTRIBS);
Martin Radev7e69f762017-07-27 14:54:13 +0300755
Olli Etuaho44ae8992018-08-20 15:37:09 +0300756 GLVertexArray vao;
757 GLBuffer vertexBuffer;
758 GLBuffer indexBuffer;
759 initVAO(vao, vertexBuffer, indexBuffer);
760
Martin Radev7e69f762017-07-27 14:54:13 +0300761 GLBuffer tbo;
762 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
Jamie Madill04c084d2018-08-08 15:49:28 -0400763 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 16u, nullptr, GL_STATIC_DRAW);
Martin Radev7e69f762017-07-27 14:54:13 +0300764
765 GLTransformFeedback transformFeedback;
766 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
Olli Etuaho3755c482017-10-13 15:40:26 +0300767
768 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
769
Jamie Madill04c084d2018-08-08 15:49:28 -0400770 glUseProgram(dualViewProgram);
Martin Radev7e69f762017-07-27 14:54:13 +0300771 glBeginTransformFeedback(GL_TRIANGLES);
772 ASSERT_GL_NO_ERROR();
773
Olli Etuaho44ae8992018-08-20 15:37:09 +0300774 GLFramebuffer fbo;
775 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
776
Mingyu Hu7d64c482019-03-12 14:27:40 -0700777 GLTexture tex2DArray;
778 initOnePixelColorTexture2DMultiLayered(tex2DArray);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300779
shrekshao15ce8222019-03-18 19:25:21 -0700780 GLenum bufs[] = {GL_NONE};
781 glDrawBuffers(1, bufs);
782
Martin Radev7e69f762017-07-27 14:54:13 +0300783 // Check that drawArrays generates an error when there is an active transform feedback object
784 // and the number of views in the draw framebuffer is greater than 1.
785 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700786 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
Martin Radev7e69f762017-07-27 14:54:13 +0300787 glDrawArrays(GL_TRIANGLES, 0, 3);
788 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
789 }
790
Jamie Madill04c084d2018-08-08 15:49:28 -0400791 glEndTransformFeedback();
792
793 // Ending transform feedback should allow the draw to succeed.
794 {
795 glDrawArrays(GL_TRIANGLES, 0, 3);
796 EXPECT_GL_NO_ERROR();
797 }
798
Jamie Madill3a256222018-12-08 09:56:39 -0500799 // A paused transform feedback should not trigger an error.
Jamie Madill04c084d2018-08-08 15:49:28 -0400800 glBeginTransformFeedback(GL_TRIANGLES);
801 glPauseTransformFeedback();
802 ASSERT_GL_NO_ERROR();
803
804 glDrawArrays(GL_TRIANGLES, 0, 3);
Jamie Madill3a256222018-12-08 09:56:39 -0500805 ASSERT_GL_NO_ERROR();
Jamie Madill04c084d2018-08-08 15:49:28 -0400806
807 // Unbind transform feedback - should succeed.
808 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
809 glDrawArrays(GL_TRIANGLES, 0, 3);
810 ASSERT_GL_NO_ERROR();
811
Jamie Madill3a256222018-12-08 09:56:39 -0500812 // Rebind paused transform feedback - should succeed.
Jamie Madill04c084d2018-08-08 15:49:28 -0400813 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
814 glDrawArrays(GL_TRIANGLES, 0, 3);
Jamie Madill3a256222018-12-08 09:56:39 -0500815 ASSERT_GL_NO_ERROR();
Jamie Madill04c084d2018-08-08 15:49:28 -0400816
817 glResumeTransformFeedback();
818 glEndTransformFeedback();
819
820 glUseProgram(singleViewProgram);
821 glBeginTransformFeedback(GL_TRIANGLES);
822 ASSERT_GL_NO_ERROR();
823
Mingyu Hu7d64c482019-03-12 14:27:40 -0700824 GLTexture tex2D;
825 initOnePixelColorTexture2DSingleLayered(tex2D);
826
Martin Radev7e69f762017-07-27 14:54:13 +0300827 // Check that drawArrays does not generate an error when the number of views in the draw
828 // framebuffer is 1.
829 {
Mingyu Hu7d64c482019-03-12 14:27:40 -0700830 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Martin Radev7e69f762017-07-27 14:54:13 +0300831 glDrawArrays(GL_TRIANGLES, 0, 3);
832 EXPECT_GL_NO_ERROR();
833 }
834
835 glEndTransformFeedback();
836}
837
Martin Radevffe754b2017-07-31 10:38:07 +0300838// The test verifies that glDraw*:
839// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
840// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
841// 2) does not generate any error if the number of views in the draw framebuffer is 1.
842TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
843{
Yunchao He9550c602018-02-13 14:47:05 +0800844 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
Jamie Madillb8149072019-04-30 16:14:44 -0400845 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_disjoint_timer_query"));
Martin Radevffe754b2017-07-31 10:38:07 +0300846
Mingyu Huebab6702019-04-19 14:36:45 -0700847 ANGLE_GL_PROGRAM(dualViewProgram, DualViewVS(GetParam().mMultiviewExtension).c_str(),
848 DualViewFS(GetParam().mMultiviewExtension).c_str());
Olli Etuaho44ae8992018-08-20 15:37:09 +0300849
Jamie Madill35cd7332018-12-02 12:03:33 -0500850 constexpr char kVS[] =
Martin Radevffe754b2017-07-31 10:38:07 +0300851 "#version 300 es\n"
852 "void main()\n"
853 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500854 constexpr char kFS[] =
Martin Radevffe754b2017-07-31 10:38:07 +0300855 "#version 300 es\n"
856 "precision mediump float;\n"
857 "void main()\n"
858 "{}\n";
Jamie Madill35cd7332018-12-02 12:03:33 -0500859 ANGLE_GL_PROGRAM(singleViewProgram, kVS, kFS);
Jamie Madill04c084d2018-08-08 15:49:28 -0400860 glUseProgram(singleViewProgram);
Martin Radevffe754b2017-07-31 10:38:07 +0300861
Olli Etuaho44ae8992018-08-20 15:37:09 +0300862 GLVertexArray vao;
863 GLBuffer vertexBuffer;
864 GLBuffer indexBuffer;
865 initVAO(vao, vertexBuffer, indexBuffer);
866
Martin Radevffe754b2017-07-31 10:38:07 +0300867 GLuint query = 0u;
868 glGenQueriesEXT(1, &query);
869 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
870
Olli Etuaho44ae8992018-08-20 15:37:09 +0300871 GLFramebuffer fbo;
872 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
873
Mingyu Hu7d64c482019-03-12 14:27:40 -0700874 GLTexture tex2DArr;
875 initOnePixelColorTexture2DMultiLayered(tex2DArr);
Olli Etuaho44ae8992018-08-20 15:37:09 +0300876
shrekshao15ce8222019-03-18 19:25:21 -0700877 GLenum bufs[] = {GL_NONE};
878 glDrawBuffers(1, bufs);
879
Martin Radevffe754b2017-07-31 10:38:07 +0300880 // Check first case.
881 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300882 glUseProgram(dualViewProgram);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700883 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArr, 0, 0, 2);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300884 glClear(GL_COLOR_BUFFER_BIT);
885 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radevffe754b2017-07-31 10:38:07 +0300886 glDrawArrays(GL_TRIANGLES, 0, 3);
887 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
888 }
889
Mingyu Hu7d64c482019-03-12 14:27:40 -0700890 GLTexture tex2D;
891 initOnePixelColorTexture2DSingleLayered(tex2D);
892
Martin Radevffe754b2017-07-31 10:38:07 +0300893 // Check second case.
894 {
Jamie Madill04c084d2018-08-08 15:49:28 -0400895 glUseProgram(singleViewProgram);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700896 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
Olli Etuaho94c91a92018-07-19 15:10:24 +0300897 glClear(GL_COLOR_BUFFER_BIT);
898 EXPECT_GL_NO_ERROR();
Martin Radevffe754b2017-07-31 10:38:07 +0300899 glDrawArrays(GL_TRIANGLES, 0, 3);
900 EXPECT_GL_NO_ERROR();
901 }
902
903 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
904 glDeleteQueries(1, &query);
Jamie Madill04c084d2018-08-08 15:49:28 -0400905
906 // Check starting a query after a successful draw.
907 {
Olli Etuaho44ae8992018-08-20 15:37:09 +0300908 glUseProgram(dualViewProgram);
Mingyu Hu7d64c482019-03-12 14:27:40 -0700909 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArr, 0, 0, 2);
Jamie Madill04c084d2018-08-08 15:49:28 -0400910 glClear(GL_COLOR_BUFFER_BIT);
911 EXPECT_GL_NO_ERROR();
912 glDrawArrays(GL_TRIANGLES, 0, 3);
913 EXPECT_GL_NO_ERROR();
914
915 glGenQueriesEXT(1, &query);
916 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
917
918 glDrawArrays(GL_TRIANGLES, 0, 3);
919 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
920
921 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
922 glDrawArrays(GL_TRIANGLES, 0, 3);
923 EXPECT_GL_NO_ERROR();
924
925 glDeleteQueries(1, &query);
926 }
Martin Radevffe754b2017-07-31 10:38:07 +0300927}
928
Martin Radev8f276e22017-05-30 12:05:52 +0300929// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300930TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300931{
Jamie Madill3a256222018-12-08 09:56:39 -0500932 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
933
Martin Radev8f276e22017-05-30 12:05:52 +0300934 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
935 ASSERT_GL_NO_ERROR();
936
937 checkOutput();
938}
939
940// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300941TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300942{
Jamie Madill3a256222018-12-08 09:56:39 -0500943 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
944
Martin Radev8f276e22017-05-30 12:05:52 +0300945 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
946 ASSERT_GL_NO_ERROR();
947
948 checkOutput();
949}
950
951// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300952TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300953{
Jamie Madill3a256222018-12-08 09:56:39 -0500954 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
955
Martin Radev8f276e22017-05-30 12:05:52 +0300956 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
957 ASSERT_GL_NO_ERROR();
958
959 checkOutput();
960}
961
962// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300963TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300964{
Jamie Madill3a256222018-12-08 09:56:39 -0500965 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev8f276e22017-05-30 12:05:52 +0300966
Mingyu Huebab6702019-04-19 14:36:45 -0700967 const std::string VS =
Martin Radev8f276e22017-05-30 12:05:52 +0300968 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -0700969 "#extension " +
970 extensionName() +
971 " : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300972 "layout(num_views = 4) in;\n"
973 "in vec4 vPosition;\n"
974 "void main()\n"
975 "{\n"
976 " if (gl_ViewID_OVR == 0u) {\n"
977 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
978 " } else if (gl_ViewID_OVR == 1u) {\n"
979 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
980 " } else if (gl_ViewID_OVR == 2u) {\n"
981 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
982 " } else {\n"
983 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
984 " }"
985 " gl_Position.yzw = vPosition.yzw;\n"
986 "}\n";
987
Mingyu Huebab6702019-04-19 14:36:45 -0700988 const std::string FS =
Martin Radev8f276e22017-05-30 12:05:52 +0300989 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -0700990 "#extension " +
991 extensionName() +
992 " : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300993 "precision mediump float;\n"
994 "out vec4 col;\n"
995 "void main()\n"
996 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300997 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300998 "}\n";
999
Olli Etuaho4836acc2018-08-20 15:23:18 +03001000 updateFBOs(4, 1, 4);
Mingyu Huebab6702019-04-19 14:36:45 -07001001 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radev8f276e22017-05-30 12:05:52 +03001002
1003 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1004 ASSERT_GL_NO_ERROR();
1005
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001006 resolveMultisampledFBO();
Martin Radev8f276e22017-05-30 12:05:52 +03001007 for (int i = 0; i < 4; ++i)
1008 {
1009 for (int j = 0; j < 4; ++j)
1010 {
Martin Radev8f276e22017-05-30 12:05:52 +03001011 if (i == j)
1012 {
Martin Radev67a8a012017-09-08 13:03:52 +03001013 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +03001014 }
1015 else
1016 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001017 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +03001018 }
1019 }
1020 }
1021 EXPECT_GL_NO_ERROR();
1022}
1023
1024// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +03001025TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +03001026{
Jamie Madill3a256222018-12-08 09:56:39 -05001027 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev8f276e22017-05-30 12:05:52 +03001028
Mingyu Huebab6702019-04-19 14:36:45 -07001029 const std::string VS =
Martin Radev8f276e22017-05-30 12:05:52 +03001030 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001031 "#extension " +
1032 extensionName() +
1033 ": require\n"
Martin Radev8f276e22017-05-30 12:05:52 +03001034 "layout(num_views = 2) in;\n"
1035 "in vec4 vPosition;\n"
1036 "void main()\n"
1037 "{\n"
1038 " vec4 p = vPosition;\n"
1039 " if (gl_InstanceID == 1){\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001040 " p.y = p.y * 0.5 + 0.5;\n"
Martin Radev8f276e22017-05-30 12:05:52 +03001041 " } else {\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001042 " p.y = p.y * 0.5 - 0.5;\n"
Martin Radev8f276e22017-05-30 12:05:52 +03001043 " }\n"
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001044 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x * 0.5 + 0.5 : p.x * 0.5 - 0.5);\n"
Martin Radev8f276e22017-05-30 12:05:52 +03001045 " gl_Position.yzw = p.yzw;\n"
1046 "}\n";
1047
Mingyu Huebab6702019-04-19 14:36:45 -07001048 const std::string FS =
Martin Radev8f276e22017-05-30 12:05:52 +03001049 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001050 "#extension " +
1051 extensionName() +
1052 ": require\n"
Martin Radev8f276e22017-05-30 12:05:52 +03001053 "precision mediump float;\n"
1054 "out vec4 col;\n"
1055 "void main()\n"
1056 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001057 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +03001058 "}\n";
1059
Martin Radev3c25ad02017-08-22 17:36:53 +03001060 const int kViewWidth = 2;
1061 const int kViewHeight = 2;
1062 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001063 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Mingyu Huebab6702019-04-19 14:36:45 -07001064 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radev8f276e22017-05-30 12:05:52 +03001065
Martin Radev67a8a012017-09-08 13:03:52 +03001066 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 2u);
Martin Radev8f276e22017-05-30 12:05:52 +03001067 ASSERT_GL_NO_ERROR();
1068
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001069 resolveMultisampledFBO();
1070
Martin Radev67a8a012017-09-08 13:03:52 +03001071 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
1072 {{255, 0}, {255, 0}}};
Martin Radev3c25ad02017-08-22 17:36:53 +03001073
1074 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +03001075 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001076 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +03001077 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001078 for (int x = 0; x < 2; ++x)
1079 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001080 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][y][x], 0,
1081 expectedGreenChannel[view][y][x]),
Martin Radev3c25ad02017-08-22 17:36:53 +03001082 GetViewColor(x, y, view));
1083 }
Martin Radev8f276e22017-05-30 12:05:52 +03001084 }
1085 }
1086}
1087
Martin Radev553590a2017-07-31 16:40:39 +03001088// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
1089// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
1090// offset of each quad are passed as separate attributes which are indexed based on the
1091// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
1092// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
1093// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
1094// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +03001095TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +03001096{
Jamie Madill3a256222018-12-08 09:56:39 -05001097 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev553590a2017-07-31 16:40:39 +03001098
Corentin Wallez02cd1522018-08-22 13:46:21 +02001099 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001100 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001101 if (IsWindows() && IsD3D11())
1102 {
1103 ignoreD3D11SDKLayersWarnings();
1104 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001105
Mingyu Huebab6702019-04-19 14:36:45 -07001106 const std::string VS =
Martin Radev553590a2017-07-31 16:40:39 +03001107 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001108 "#extension " +
1109 extensionName() +
1110 " : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001111 "layout(num_views = 2) in;\n"
1112 "in vec3 vPosition;\n"
1113 "in float offsetX;\n"
1114 "in float offsetY;\n"
1115 "void main()\n"
1116 "{\n"
1117 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001118 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001119 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
1120 " gl_Position.yzw = p.yzw;\n"
1121 "}\n";
1122
Mingyu Huebab6702019-04-19 14:36:45 -07001123 const std::string FS =
Martin Radev553590a2017-07-31 16:40:39 +03001124 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001125 "#extension " +
1126 extensionName() +
1127 ": require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001128 "precision mediump float;\n"
1129 "out vec4 col;\n"
1130 "void main()\n"
1131 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001132 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001133 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +03001134
1135 const int kViewWidth = 4;
1136 const int kViewHeight = 4;
1137 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001138 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Mingyu Huebab6702019-04-19 14:36:45 -07001139 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radev553590a2017-07-31 16:40:39 +03001140
1141 GLBuffer xOffsetVBO;
1142 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1143 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
1144 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
1145 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1146 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1147 glVertexAttribDivisor(xOffsetLoc, 3);
1148 glEnableVertexAttribArray(xOffsetLoc);
1149
1150 GLBuffer yOffsetVBO;
1151 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1152 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1153 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1154 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1155 glVertexAttribDivisor(yOffsetLoc, 1);
1156 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1157 glEnableVertexAttribArray(yOffsetLoc);
1158
Martin Radev67a8a012017-09-08 13:03:52 +03001159 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev553590a2017-07-31 16:40:39 +03001160 ASSERT_GL_NO_ERROR();
1161
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001162 resolveMultisampledFBO();
1163
Martin Radev67a8a012017-09-08 13:03:52 +03001164 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001165 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1166 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1167 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +03001168 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001169 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +03001170 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001171 for (int col = 0; col < 4; ++col)
1172 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03001173 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0,
1174 expectedGreenChannel[view][row][col]),
Martin Radev3c25ad02017-08-22 17:36:53 +03001175 GetViewColor(col, row, view));
1176 }
Martin Radev553590a2017-07-31 16:40:39 +03001177 }
1178 }
1179}
1180
1181// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1182// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +03001183TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +03001184{
Jamie Madill3a256222018-12-08 09:56:39 -05001185 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
Martin Radev553590a2017-07-31 16:40:39 +03001186
Olli Etuaho4836acc2018-08-20 15:23:18 +03001187 updateFBOs(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +03001188
1189 // Create multiview program.
Mingyu Huebab6702019-04-19 14:36:45 -07001190 const std::string VS =
Martin Radev553590a2017-07-31 16:40:39 +03001191 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001192 "#extension " +
1193 extensionName() +
1194 ": require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001195 "layout(num_views = 2) in;\n"
1196 "layout(location = 0) in vec2 vPosition;\n"
1197 "layout(location = 1) in float offsetX;\n"
1198 "void main()\n"
1199 "{\n"
1200 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1201 " p.x += offsetX;\n"
1202 " gl_Position = p;\n"
1203 "}\n";
1204
Mingyu Huebab6702019-04-19 14:36:45 -07001205 const std::string FS =
Martin Radev553590a2017-07-31 16:40:39 +03001206 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001207 "#extension " +
1208 extensionName() +
1209 " : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001210 "precision mediump float;\n"
1211 "out vec4 col;\n"
1212 "void main()\n"
1213 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001214 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001215 "}\n";
1216
Mingyu Huebab6702019-04-19 14:36:45 -07001217 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radev553590a2017-07-31 16:40:39 +03001218
Jamie Madill35cd7332018-12-02 12:03:33 -05001219 constexpr char kDummyVS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001220 "#version 300 es\n"
1221 "layout(location = 0) in vec2 vPosition;\n"
1222 "layout(location = 1) in float offsetX;\n"
1223 "void main()\n"
1224 "{\n"
1225 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1226 "}\n";
1227
Jamie Madill35cd7332018-12-02 12:03:33 -05001228 constexpr char kDummyFS[] =
Martin Radev553590a2017-07-31 16:40:39 +03001229 "#version 300 es\n"
1230 "precision mediump float;\n"
1231 "out vec4 col;\n"
1232 "void main()\n"
1233 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001234 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001235 "}\n";
1236
Jamie Madill35cd7332018-12-02 12:03:33 -05001237 ANGLE_GL_PROGRAM(dummyProgram, kDummyVS, kDummyFS);
Martin Radev553590a2017-07-31 16:40:39 +03001238
1239 GLBuffer xOffsetVBO;
1240 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1241 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1242 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1243 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1244
1245 GLBuffer vertexVBO;
1246 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1247 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1248 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1249 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1250
1251 GLVertexArray vao[2];
1252 for (size_t i = 0u; i < 2u; ++i)
1253 {
1254 glBindVertexArray(vao[i]);
1255
1256 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1257 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1258 glEnableVertexAttribArray(0);
1259
1260 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1261 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1262 glEnableVertexAttribArray(1);
1263 }
1264 ASSERT_GL_NO_ERROR();
1265
1266 glViewport(0, 0, 1, 1);
1267 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001268 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001269 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001270
1271 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1272 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1273 // bits are cleared.
1274 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001275 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1276 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001277 glBindVertexArray(vao[0]);
1278 glVertexAttribDivisor(1, 0);
1279 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1280 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001281 ASSERT_GL_NO_ERROR();
1282
1283 // Check that vertexAttribDivisor uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001284 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001285 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001286 glUseProgram(program);
1287 glVertexAttribDivisor(1, 1);
1288 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001289
1290 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001291 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1292 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001293
1294 // Clear the buffers and propagate divisor to the driver.
1295 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1296 // dirty bits when useProgram is called.
1297 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001298 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1299 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001300 glVertexAttribDivisor(1, 1);
1301 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1302 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001303 ASSERT_GL_NO_ERROR();
1304
1305 // Check that useProgram uses the number of views to update the divisor.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001306 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001307 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001308 glUseProgram(program);
1309 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001310
1311 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001312 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1313 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001314
1315 // We go through similar steps as before.
1316 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001317 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1318 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001319 glVertexAttribDivisor(1, 1);
1320 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1321 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001322 ASSERT_GL_NO_ERROR();
1323
1324 // Check that bindVertexArray uses the number of views to update the divisor.
1325 {
1326 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1327 // divisor for vao[1] only.
Olli Etuaho4836acc2018-08-20 15:23:18 +03001328 bindMemberDrawFramebuffer();
Martin Radevda8e2572017-09-12 17:21:16 +03001329 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001330 glBindVertexArray(vao[1]);
1331 glUseProgram(program);
1332 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001333 glBindVertexArray(0);
1334 ASSERT_GL_NO_ERROR();
1335 }
1336 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1337 // adjusts the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001338 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001339 glBindVertexArray(vao[0]);
1340 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001341
1342 resolveMultisampledFBO();
Martin Radev67a8a012017-09-08 13:03:52 +03001343 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1344 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001345}
1346
Martin Radev0d671c92017-08-10 16:41:52 +03001347// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1348// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001349TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001350{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001351 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1352 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001353
Mingyu Huebab6702019-04-19 14:36:45 -07001354 const std::string VS =
Martin Radev0d671c92017-08-10 16:41:52 +03001355 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001356 "#extension " +
1357 extensionName() +
1358 ": require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001359 "layout(num_views = 2) in;\n"
1360 "in vec3 vPosition;\n"
1361 "void main()\n"
1362 "{\n"
1363 " gl_Position.x = 2.0;\n"
1364 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1365 "}\n";
1366
Mingyu Huebab6702019-04-19 14:36:45 -07001367 const std::string FS =
Martin Radev0d671c92017-08-10 16:41:52 +03001368 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001369 "#extension " +
1370 extensionName() +
1371 " : require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001372 "precision mediump float;\n"
1373 "out vec4 col;\n"
1374 "void main()\n"
1375 "{\n"
1376 " col = vec4(1,0,0,0);\n"
1377 "}\n";
Mingyu Huebab6702019-04-19 14:36:45 -07001378 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Olli Etuaho4836acc2018-08-20 15:23:18 +03001379 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001380
1381 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1382 ASSERT_GL_NO_ERROR();
1383 EXPECT_GL_FALSE(result);
1384}
1385
1386// Test that there are fragments passing the occlusion query if only view 0 can produce
1387// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001388TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001389{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001390 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1391 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001392
Mingyu Huebab6702019-04-19 14:36:45 -07001393 const std::string VS =
Martin Radev0d671c92017-08-10 16:41:52 +03001394 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001395 "#extension " +
1396 extensionName() +
1397 ": require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001398 "layout(num_views = 2) in;\n"
1399 "in vec3 vPosition;\n"
1400 "void main()\n"
1401 "{\n"
1402 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1403 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1404 "}\n";
1405
Mingyu Huebab6702019-04-19 14:36:45 -07001406 const std::string FS =
Martin Radev0d671c92017-08-10 16:41:52 +03001407 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001408 "#extension " +
1409 extensionName() +
1410 ": require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001411 "precision mediump float;\n"
1412 "out vec4 col;\n"
1413 "void main()\n"
1414 "{\n"
1415 " col = vec4(1,0,0,0);\n"
1416 "}\n";
Mingyu Huebab6702019-04-19 14:36:45 -07001417 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Olli Etuaho4836acc2018-08-20 15:23:18 +03001418 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001419
1420 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1421 ASSERT_GL_NO_ERROR();
1422 EXPECT_GL_TRUE(result);
1423}
1424
1425// Test that there are fragments passing the occlusion query if only view 1 can produce
1426// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001427TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001428{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001429 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1430 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001431
Mingyu Huebab6702019-04-19 14:36:45 -07001432 const std::string VS =
Martin Radev0d671c92017-08-10 16:41:52 +03001433 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001434 "#extension " +
1435 extensionName() +
1436 ": require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001437 "layout(num_views = 2) in;\n"
1438 "in vec3 vPosition;\n"
1439 "void main()\n"
1440 "{\n"
1441 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1442 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1443 "}\n";
1444
Mingyu Huebab6702019-04-19 14:36:45 -07001445 const std::string FS =
Martin Radev0d671c92017-08-10 16:41:52 +03001446 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001447 "#extension " +
1448 extensionName() +
1449 ": require\n"
Martin Radev0d671c92017-08-10 16:41:52 +03001450 "precision mediump float;\n"
1451 "out vec4 col;\n"
1452 "void main()\n"
1453 "{\n"
1454 " col = vec4(1,0,0,0);\n"
1455 "}\n";
Mingyu Huebab6702019-04-19 14:36:45 -07001456 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Olli Etuaho4836acc2018-08-20 15:23:18 +03001457 updateFBOs(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001458
1459 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1460 ASSERT_GL_NO_ERROR();
1461 EXPECT_GL_TRUE(result);
1462}
1463
Martin Radev41ac68e2017-06-06 12:16:58 +03001464// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1465// compiles and links without an error.
1466TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1467{
1468 if (!requestMultiviewExtension())
1469 {
1470 return;
1471 }
1472
Mingyu Huebab6702019-04-19 14:36:45 -07001473 const std::string VS =
Martin Radev41ac68e2017-06-06 12:16:58 +03001474 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001475 "#extension " +
1476 extensionName() +
1477 ": require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001478 "layout(num_views = 2) in;\n"
1479 "void main()\n"
1480 "{\n"
1481 "}\n";
1482
Mingyu Huebab6702019-04-19 14:36:45 -07001483 const std::string FS =
Martin Radev41ac68e2017-06-06 12:16:58 +03001484 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001485 "#extension " +
1486 extensionName() +
1487 ": require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001488 "precision mediump float;\n"
1489 "void main()\n"
1490 "{\n"
1491 "}\n";
1492
Mingyu Huebab6702019-04-19 14:36:45 -07001493 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radev41ac68e2017-06-06 12:16:58 +03001494 glUseProgram(program);
1495
1496 EXPECT_GL_NO_ERROR();
1497}
1498
1499// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1500// without an error.
1501TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1502{
1503 if (!requestMultiviewExtension())
1504 {
1505 return;
1506 }
1507
Mingyu Huebab6702019-04-19 14:36:45 -07001508 const std::string VS =
Martin Radev41ac68e2017-06-06 12:16:58 +03001509 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001510 "#extension " +
1511 extensionName() +
1512 ": require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001513 "layout(num_views = 2) in;\n"
1514 "void main()\n"
1515 "{\n"
1516 " if (gl_ViewID_OVR == 0u) {\n"
1517 " gl_Position = vec4(1,0,0,1);\n"
1518 " } else {\n"
1519 " gl_Position = vec4(-1,0,0,1);\n"
1520 " }\n"
1521 "}\n";
1522
Mingyu Huebab6702019-04-19 14:36:45 -07001523 const std::string FS =
Martin Radev41ac68e2017-06-06 12:16:58 +03001524 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001525 "#extension " +
1526 extensionName() +
1527 ": require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001528 "precision mediump float;\n"
1529 "void main()\n"
1530 "{\n"
1531 "}\n";
1532
Mingyu Huebab6702019-04-19 14:36:45 -07001533 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radev41ac68e2017-06-06 12:16:58 +03001534 glUseProgram(program);
1535
1536 EXPECT_GL_NO_ERROR();
1537}
1538
1539// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1540// without an error.
1541TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1542{
1543 if (!requestMultiviewExtension())
1544 {
1545 return;
1546 }
1547
Mingyu Huebab6702019-04-19 14:36:45 -07001548 const std::string VS =
Martin Radev41ac68e2017-06-06 12:16:58 +03001549 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001550 "#extension " +
1551 extensionName() +
1552 ": require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001553 "layout(num_views = 2) in;\n"
1554 "void main()\n"
1555 "{\n"
1556 "}\n";
1557
Mingyu Huebab6702019-04-19 14:36:45 -07001558 const std::string FS =
Martin Radev41ac68e2017-06-06 12:16:58 +03001559 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001560 "#extension " +
1561 extensionName() +
1562 ": require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001563 "precision mediump float;\n"
1564 "out vec4 col;\n"
1565 "void main()\n"
1566 "{\n"
1567 " if (gl_ViewID_OVR == 0u) {\n"
1568 " col = vec4(1,0,0,1);\n"
1569 " } else {\n"
1570 " col = vec4(-1,0,0,1);\n"
1571 " }\n"
1572 "}\n";
1573
Mingyu Huebab6702019-04-19 14:36:45 -07001574 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radev41ac68e2017-06-06 12:16:58 +03001575 glUseProgram(program);
1576
1577 EXPECT_GL_NO_ERROR();
1578}
1579
Martin Radev61bd9992017-08-11 13:10:55 +03001580// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001581TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001582{
1583 if (!requestMultiviewExtension())
1584 {
1585 return;
1586 }
1587
Geoff Lang25858162017-11-06 11:25:58 -05001588 // Test failing on P400 graphics card (anglebug.com/2228)
1589 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1590
Mingyu Huebab6702019-04-19 14:36:45 -07001591 const std::string VS =
Martin Radev61bd9992017-08-11 13:10:55 +03001592 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001593 "#extension " +
1594 extensionName() +
1595 ": require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001596 "layout(num_views = 2) in;\n"
1597 "layout(location=0) in vec2 vPosition;\n"
1598 "void main()\n"
1599 "{\n"
1600 " gl_PointSize = 1.0;\n"
1601 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1602 "}\n";
1603
Mingyu Huebab6702019-04-19 14:36:45 -07001604 const std::string FS =
Martin Radev61bd9992017-08-11 13:10:55 +03001605 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001606 "#extension " +
1607 extensionName() +
1608 ": require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001609 "precision mediump float;\n"
1610 "out vec4 col;\n"
1611 "void main()\n"
1612 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001613 " col = vec4(0,1,0,1);\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001614 "}\n";
Mingyu Huebab6702019-04-19 14:36:45 -07001615 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radev61bd9992017-08-11 13:10:55 +03001616 glUseProgram(program);
1617
Martin Radev3c25ad02017-08-22 17:36:53 +03001618 const int kViewWidth = 4;
1619 const int kViewHeight = 2;
1620 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001621 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001622
1623 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1624 std::vector<Vector2> vertexDataInClipSpace =
1625 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1626 setupGeometry(vertexDataInClipSpace);
1627
1628 glDrawArrays(GL_POINTS, 0, 2);
1629
Martin Radev67a8a012017-09-08 13:03:52 +03001630 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001631 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001632 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001633}
1634
1635// The test checks that GL_LINES is correctly rendered.
1636// The behavior of this test is not guaranteed by the spec:
1637// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1638// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1639// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1640// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001641TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001642{
1643 if (!requestMultiviewExtension())
1644 {
1645 return;
1646 }
1647
Mingyu Huebab6702019-04-19 14:36:45 -07001648 GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
Martin Radev61bd9992017-08-11 13:10:55 +03001649 ASSERT_NE(program, 0u);
1650 glUseProgram(program);
1651 ASSERT_GL_NO_ERROR();
1652
Martin Radev3c25ad02017-08-22 17:36:53 +03001653 const int kViewWidth = 4;
1654 const int kViewHeight = 2;
1655 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001656 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001657
1658 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1659 std::vector<Vector2> vertexDataInClipSpace =
1660 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1661 setupGeometry(vertexDataInClipSpace);
1662
1663 glDrawArrays(GL_LINES, 0, 2);
1664
Martin Radev67a8a012017-09-08 13:03:52 +03001665 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001666 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001667 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001668
1669 glDeleteProgram(program);
1670}
1671
1672// The test checks that GL_LINE_STRIP is correctly rendered.
1673// The behavior of this test is not guaranteed by the spec:
1674// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1675// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1676// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1677// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001678TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001679{
1680 if (!requestMultiviewExtension())
1681 {
1682 return;
1683 }
1684
Mingyu Huebab6702019-04-19 14:36:45 -07001685 GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
Martin Radev61bd9992017-08-11 13:10:55 +03001686 ASSERT_NE(program, 0u);
1687 glUseProgram(program);
1688 ASSERT_GL_NO_ERROR();
1689
Martin Radev3c25ad02017-08-22 17:36:53 +03001690 const int kViewWidth = 4;
1691 const int kViewHeight = 2;
1692 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001693 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001694
1695 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1696 std::vector<Vector2> vertexDataInClipSpace =
1697 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1698 setupGeometry(vertexDataInClipSpace);
1699
1700 glDrawArrays(GL_LINE_STRIP, 0, 3);
1701
Martin Radev67a8a012017-09-08 13:03:52 +03001702 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001703 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001704 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001705
1706 glDeleteProgram(program);
1707}
1708
1709// The test checks that GL_LINE_LOOP is correctly rendered.
1710// The behavior of this test is not guaranteed by the spec:
1711// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1712// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1713// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1714// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001715TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001716{
1717 if (!requestMultiviewExtension())
1718 {
1719 return;
1720 }
1721
Mingyu Huebab6702019-04-19 14:36:45 -07001722 GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
Martin Radev61bd9992017-08-11 13:10:55 +03001723 ASSERT_NE(program, 0u);
1724 glUseProgram(program);
1725 ASSERT_GL_NO_ERROR();
1726
Martin Radev3c25ad02017-08-22 17:36:53 +03001727 const int kViewWidth = 4;
1728 const int kViewHeight = 4;
1729 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001730 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001731
1732 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1733 Vector2I(0, 3)};
1734 std::vector<Vector2> vertexDataInClipSpace =
1735 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1736 setupGeometry(vertexDataInClipSpace);
1737
1738 glDrawArrays(GL_LINE_LOOP, 0, 4);
1739
Martin Radev67a8a012017-09-08 13:03:52 +03001740 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001741 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1742 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001743 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001744
1745 glDeleteProgram(program);
1746}
1747
1748// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001749TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001750{
1751 if (!requestMultiviewExtension())
1752 {
1753 return;
1754 }
1755
Mingyu Huebab6702019-04-19 14:36:45 -07001756 GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
Martin Radev61bd9992017-08-11 13:10:55 +03001757 ASSERT_NE(program, 0u);
1758 glUseProgram(program);
1759 ASSERT_GL_NO_ERROR();
1760
1761 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1762 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1763 setupGeometry(vertexDataInClipSpace);
1764
Martin Radev3c25ad02017-08-22 17:36:53 +03001765 const int kViewWidth = 2;
1766 const int kViewHeight = 2;
1767 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001768 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001769
1770 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1771
Martin Radev67a8a012017-09-08 13:03:52 +03001772 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1773 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1774 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001775
1776 glDeleteProgram(program);
1777}
1778
1779// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001780TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001781{
1782 if (!requestMultiviewExtension())
1783 {
1784 return;
1785 }
1786
Mingyu Huebab6702019-04-19 14:36:45 -07001787 GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
Martin Radev61bd9992017-08-11 13:10:55 +03001788 ASSERT_NE(program, 0u);
1789 glUseProgram(program);
1790 ASSERT_GL_NO_ERROR();
1791
1792 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1793 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1794 setupGeometry(vertexDataInClipSpace);
1795
Martin Radev3c25ad02017-08-22 17:36:53 +03001796 const int kViewWidth = 2;
1797 const int kViewHeight = 2;
1798 const int kNumViews = 2;
Olli Etuaho4836acc2018-08-20 15:23:18 +03001799 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001800
1801 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1802
Martin Radev67a8a012017-09-08 13:03:52 +03001803 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1804 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1805 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001806
1807 glDeleteProgram(program);
1808}
1809
Martin Radev0abb7a22017-08-28 15:34:45 +03001810// Verify that re-linking a program adjusts the attribute divisor.
1811// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1812// to each other. The quads' position and color depend on the corresponding attribute divisors.
1813TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1814{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001815 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev0abb7a22017-08-28 15:34:45 +03001816 {
1817 return;
1818 }
1819
Corentin Wallez02cd1522018-08-22 13:46:21 +02001820 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
Olli Etuaho44ae8992018-08-20 15:37:09 +03001821 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001822 if (IsWindows() && IsD3D11())
1823 {
1824 ignoreD3D11SDKLayersWarnings();
1825 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001826
Martin Radev0abb7a22017-08-28 15:34:45 +03001827 const int kViewWidth = 4;
1828 const int kViewHeight = 1;
1829 const int kNumViews = 2;
1830
Mingyu Huebab6702019-04-19 14:36:45 -07001831 const std::string FS =
Martin Radev0abb7a22017-08-28 15:34:45 +03001832 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001833 "#extension " +
1834 extensionName() +
1835 ": require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001836 "precision mediump float;\n"
1837 "in vec4 oColor;\n"
1838 "out vec4 col;\n"
1839 "void main()\n"
1840 "{\n"
1841 " col = oColor;\n"
1842 "}\n";
1843
Mingyu Huebab6702019-04-19 14:36:45 -07001844 auto generateVertexShaderSource = [](int numViews, std::string extensionName) -> std::string {
Martin Radev0abb7a22017-08-28 15:34:45 +03001845 std::string source =
1846 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07001847 "#extension " +
1848 extensionName +
1849 ": require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001850 "layout(num_views = " +
1851 ToString(numViews) +
1852 ") in;\n"
1853 "in vec3 vPosition;\n"
1854 "in float vOffsetX;\n"
1855 "in vec4 vColor;\n"
1856 "out vec4 oColor;\n"
1857 "void main()\n"
1858 "{\n"
1859 " vec4 p = vec4(vPosition, 1.);\n"
1860 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1861 " oColor = vColor;\n"
1862 " gl_Position = p;\n"
1863 "}\n";
1864 return source;
1865 };
1866
Mingyu Huebab6702019-04-19 14:36:45 -07001867 std::string vsSource = generateVertexShaderSource(kNumViews, extensionName());
1868 ANGLE_GL_PROGRAM(program, vsSource.c_str(), FS.c_str());
Martin Radev0abb7a22017-08-28 15:34:45 +03001869 glUseProgram(program);
1870
1871 GLint positionLoc;
1872 GLBuffer xOffsetVBO;
1873 GLint xOffsetLoc;
1874 GLBuffer colorVBO;
1875 GLint colorLoc;
1876
1877 {
1878 // Initialize buffers and setup attributes.
1879 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1880 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1881 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1882 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1883 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1884 glVertexAttribDivisor(xOffsetLoc, 1);
1885 glEnableVertexAttribArray(xOffsetLoc);
1886
1887 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1888 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1889 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1890 colorLoc = glGetAttribLocation(program, "vColor");
1891 glVertexAttribDivisor(colorLoc, 2);
1892 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1893 glEnableVertexAttribArray(colorLoc);
1894
1895 positionLoc = glGetAttribLocation(program, "vPosition");
1896 }
1897
1898 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001899 updateFBOs(kViewWidth, kViewHeight, kNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001900
Martin Radev67a8a012017-09-08 13:03:52 +03001901 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001902 ASSERT_GL_NO_ERROR();
1903
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001904 resolveMultisampledFBO();
Martin Radev0abb7a22017-08-28 15:34:45 +03001905 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1906 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1907 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1908 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1909 }
1910
1911 {
1912 const int kNewNumViews = 3;
Mingyu Huebab6702019-04-19 14:36:45 -07001913 vsSource = generateVertexShaderSource(kNewNumViews, extensionName());
Olli Etuaho4836acc2018-08-20 15:23:18 +03001914 updateFBOs(kViewWidth, kViewHeight, kNewNumViews);
Martin Radev0abb7a22017-08-28 15:34:45 +03001915
Jamie Madill35cd7332018-12-02 12:03:33 -05001916 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource.c_str());
Martin Radev0abb7a22017-08-28 15:34:45 +03001917 ASSERT_NE(0u, vs);
Mingyu Huebab6702019-04-19 14:36:45 -07001918 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, FS.c_str());
Martin Radev0abb7a22017-08-28 15:34:45 +03001919 ASSERT_NE(0u, fs);
1920
1921 GLint numAttachedShaders = 0;
1922 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1923
1924 GLuint attachedShaders[2] = {0u};
1925 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1926 for (int i = 0; i < 2; ++i)
1927 {
1928 glDetachShader(program, attachedShaders[i]);
1929 }
1930
1931 glAttachShader(program, vs);
1932 glDeleteShader(vs);
1933
1934 glAttachShader(program, fs);
1935 glDeleteShader(fs);
1936
1937 glBindAttribLocation(program, positionLoc, "vPosition");
1938 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1939 glBindAttribLocation(program, colorLoc, "vColor");
1940
1941 glLinkProgram(program);
1942
Martin Radev67a8a012017-09-08 13:03:52 +03001943 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001944 ASSERT_GL_NO_ERROR();
1945
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001946 resolveMultisampledFBO();
Martin Radev0abb7a22017-08-28 15:34:45 +03001947 for (int i = 0; i < kNewNumViews; ++i)
1948 {
1949 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1950 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1951 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1952 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1953 }
1954 }
1955}
1956
Martin Radevced5c862017-08-17 16:05:29 +03001957// Test that useProgram applies the number of views in computing the final value of the attribute
1958// divisor.
1959TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1960{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03001961 if (!requestMultiviewExtension(isMultisampled()))
Martin Radevced5c862017-08-17 16:05:29 +03001962 {
1963 return;
1964 }
1965
Geoff Lang25858162017-11-06 11:25:58 -05001966 // Test failing on P400 graphics card (anglebug.com/2228)
1967 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1968
Olli Etuaho44ae8992018-08-20 15:37:09 +03001969 // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
1970 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
Olli Etuaho4b4197a2018-08-22 15:24:41 +03001971 if (IsWindows() && IsD3D11())
1972 {
1973 ignoreD3D11SDKLayersWarnings();
1974 }
Olli Etuaho44ae8992018-08-20 15:37:09 +03001975
Martin Radevced5c862017-08-17 16:05:29 +03001976 GLVertexArray vao;
1977 glBindVertexArray(vao);
1978 GLBuffer vbo;
1979 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1980 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
1981 Vector2I(3, 0)};
1982 std::vector<Vector2> vertexDataInClipSpace =
1983 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
1984 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
1985 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
1986 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1987 glEnableVertexAttribArray(0);
1988 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
1989 glVertexAttribDivisor(0, 1);
1990 ASSERT_GL_NO_ERROR();
1991
1992 // Create a program and fbo with N views and draw N instances of a point horizontally.
1993 for (int numViews = 2; numViews <= 4; ++numViews)
1994 {
Olli Etuaho4836acc2018-08-20 15:23:18 +03001995 updateFBOs(4, 1, numViews);
Martin Radevced5c862017-08-17 16:05:29 +03001996 ASSERT_GL_NO_ERROR();
1997
Mingyu Huebab6702019-04-19 14:36:45 -07001998 GLuint program = CreateSimplePassthroughProgram(numViews, GetParam().mMultiviewExtension);
Martin Radevced5c862017-08-17 16:05:29 +03001999 ASSERT_NE(program, 0u);
2000 glUseProgram(program);
2001 ASSERT_GL_NO_ERROR();
2002
2003 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
2004
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002005 resolveMultisampledFBO();
Martin Radevced5c862017-08-17 16:05:29 +03002006 for (int view = 0; view < numViews; ++view)
2007 {
2008 for (int j = 0; j < numViews; ++j)
2009 {
Martin Radev67a8a012017-09-08 13:03:52 +03002010 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03002011 }
2012 for (int j = numViews; j < 4; ++j)
2013 {
Olli Etuahoa7b35c32018-08-21 16:32:24 +03002014 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03002015 }
2016 }
2017
2018 glDeleteProgram(program);
2019 }
2020}
2021
Martin Radev72b4e1e2017-08-31 15:42:56 +03002022// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
2023TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
2024{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002025 if (!requestMultiviewExtension(isMultisampled()))
Martin Radev72b4e1e2017-08-31 15:42:56 +03002026 {
2027 return;
2028 }
2029
Mingyu Huebab6702019-04-19 14:36:45 -07002030 const std::string VS =
Martin Radev72b4e1e2017-08-31 15:42:56 +03002031 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07002032 "#extension " +
2033 extensionName() +
2034 ": require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002035 "layout(num_views = 3) in;\n"
2036 "in vec3 vPosition;\n"
2037 "void main()\n"
2038 "{\n"
2039 " gl_Position = vec4(vPosition, 1.);\n"
2040 "}\n";
2041
Mingyu Huebab6702019-04-19 14:36:45 -07002042 const std::string FS =
Martin Radev72b4e1e2017-08-31 15:42:56 +03002043 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07002044 "#extension " +
2045 extensionName() +
2046 ": require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002047 "precision mediump float;\n"
2048 "out vec4 col;\n"
2049 "void main()\n"
2050 "{\n"
2051 " if (gl_ViewID_OVR == 0u) {\n"
2052 " col = vec4(1,0,0,1);\n"
2053 " } else if (gl_ViewID_OVR == 1u) {\n"
2054 " col = vec4(0,1,0,1);\n"
2055 " } else if (gl_ViewID_OVR == 2u) {\n"
2056 " col = vec4(0,0,1,1);\n"
2057 " } else {\n"
2058 " col = vec4(0,0,0,0);\n"
2059 " }\n"
2060 "}\n";
2061
Olli Etuaho4836acc2018-08-20 15:23:18 +03002062 updateFBOs(1, 1, 3);
Mingyu Huebab6702019-04-19 14:36:45 -07002063 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002064
2065 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2066 ASSERT_GL_NO_ERROR();
2067
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002068 resolveMultisampledFBO();
Martin Radev72b4e1e2017-08-31 15:42:56 +03002069 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2070 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2071 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
2072}
2073
2074// The test checks that the inactive layers of a 2D texture array are not written to by a
2075// multi-view program.
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002076TEST_P(MultiviewLayeredRenderTest, RenderToSubrangeOfLayers)
Martin Radev72b4e1e2017-08-31 15:42:56 +03002077{
2078 if (!requestMultiviewExtension())
2079 {
2080 return;
2081 }
2082
Mingyu Huebab6702019-04-19 14:36:45 -07002083 const std::string VS =
Martin Radev72b4e1e2017-08-31 15:42:56 +03002084 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07002085 "#extension " +
2086 extensionName() +
2087 ": require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002088 "layout(num_views = 2) in;\n"
2089 "in vec3 vPosition;\n"
2090 "void main()\n"
2091 "{\n"
2092 " gl_Position = vec4(vPosition, 1.);\n"
2093 "}\n";
2094
Mingyu Huebab6702019-04-19 14:36:45 -07002095 const std::string FS =
Martin Radev72b4e1e2017-08-31 15:42:56 +03002096 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07002097 "#extension " +
2098 extensionName() +
2099 ": require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002100 "precision mediump float;\n"
2101 "out vec4 col;\n"
2102 "void main()\n"
2103 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002104 " col = vec4(0,1,0,1);\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03002105 "}\n";
2106
Olli Etuaho4836acc2018-08-20 15:23:18 +03002107 updateFBOs(1, 1, 2, 4, 1);
Mingyu Huebab6702019-04-19 14:36:45 -07002108 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002109
2110 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2111 ASSERT_GL_NO_ERROR();
2112
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002113 resolveMultisampledFBO();
Martin Radev72b4e1e2017-08-31 15:42:56 +03002114 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +03002115 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2116 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002117 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
2118}
2119
Martin Radevc1d4e552017-08-21 12:01:10 +03002120// The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
2121// potential bugs if the view is selected in the VS. The test contains a program in which the
2122// gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
2123// fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
2124// never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
2125// green for view 1.
2126TEST_P(MultiviewRenderTest, FlatInterpolation)
Martin Radev3c25ad02017-08-22 17:36:53 +03002127{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002128 if (!requestMultiviewExtension(isMultisampled()))
Martin Radevc1d4e552017-08-21 12:01:10 +03002129 {
2130 return;
2131 }
2132
Mingyu Huebab6702019-04-19 14:36:45 -07002133 const std::string VS =
Martin Radevc1d4e552017-08-21 12:01:10 +03002134 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07002135 "#extension " +
2136 extensionName() +
2137 ": require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002138 "layout(num_views = 2) in;\n"
2139 "in vec3 vPosition;\n"
2140 "flat out int oInstanceID;\n"
2141 "void main()\n"
2142 "{\n"
2143 " gl_Position = vec4(vPosition, 1.);\n"
2144 " oInstanceID = gl_InstanceID;\n"
2145 "}\n";
2146
Mingyu Huebab6702019-04-19 14:36:45 -07002147 const std::string FS =
Martin Radevc1d4e552017-08-21 12:01:10 +03002148 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07002149 "#extension " +
2150 extensionName() +
2151 ": require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002152 "precision mediump float;\n"
2153 "flat in int oInstanceID;\n"
2154 "out vec4 col;\n"
2155 "void main()\n"
2156 "{\n"
2157 " if (oInstanceID < 0) {\n"
2158 " discard;\n"
2159 " }\n"
2160 " if (gl_ViewID_OVR == 0u) {\n"
2161 " col = vec4(1,0,0,1);\n"
2162 " } else {\n"
2163 " col = vec4(0,1,0,1);\n"
2164 " }\n"
2165 "}\n";
2166
Olli Etuaho4836acc2018-08-20 15:23:18 +03002167 updateFBOs(1, 1, 2);
Mingyu Huebab6702019-04-19 14:36:45 -07002168 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Martin Radevc1d4e552017-08-21 12:01:10 +03002169
2170 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2171 ASSERT_GL_NO_ERROR();
2172
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002173 resolveMultisampledFBO();
Martin Radevc1d4e552017-08-21 12:01:10 +03002174 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2175 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +03002176}
2177
Olli Etuaho604d8732018-07-20 11:02:43 +03002178// This test assigns gl_ViewID_OVR to a flat int varying and then sets the color based on that
2179// varying in the fragment shader.
2180TEST_P(MultiviewRenderTest, FlatInterpolation2)
2181{
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002182 if (!requestMultiviewExtension(isMultisampled()))
Olli Etuaho604d8732018-07-20 11:02:43 +03002183 {
2184 return;
2185 }
2186
Mingyu Huebab6702019-04-19 14:36:45 -07002187 const std::string VS =
Olli Etuaho604d8732018-07-20 11:02:43 +03002188 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07002189 "#extension " +
2190 extensionName() +
2191 ": require\n"
Olli Etuaho604d8732018-07-20 11:02:43 +03002192 "layout(num_views = 2) in;\n"
2193 "in vec3 vPosition;\n"
2194 "flat out int flatVarying;\n"
2195 "void main()\n"
2196 "{\n"
2197 " gl_Position = vec4(vPosition, 1.);\n"
2198 " flatVarying = int(gl_ViewID_OVR);\n"
2199 "}\n";
2200
Mingyu Huebab6702019-04-19 14:36:45 -07002201 const std::string FS =
Olli Etuaho604d8732018-07-20 11:02:43 +03002202 "#version 300 es\n"
Mingyu Huebab6702019-04-19 14:36:45 -07002203 "#extension " +
2204 extensionName() +
2205 ": require\n"
Olli Etuaho604d8732018-07-20 11:02:43 +03002206 "precision mediump float;\n"
2207 "flat in int flatVarying;\n"
2208 "out vec4 col;\n"
2209 "void main()\n"
2210 "{\n"
2211 " if (flatVarying == 0) {\n"
2212 " col = vec4(1,0,0,1);\n"
2213 " } else {\n"
2214 " col = vec4(0,1,0,1);\n"
2215 " }\n"
2216 "}\n";
2217
Olli Etuaho4836acc2018-08-20 15:23:18 +03002218 updateFBOs(1, 1, 2);
Mingyu Huebab6702019-04-19 14:36:45 -07002219 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
Olli Etuaho604d8732018-07-20 11:02:43 +03002220
2221 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2222 ASSERT_GL_NO_ERROR();
2223
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002224 resolveMultisampledFBO();
Olli Etuaho604d8732018-07-20 11:02:43 +03002225 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2226 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2227}
2228
Mingyu Huebab6702019-04-19 14:36:45 -07002229MultiviewRenderTestParams VertexShaderOpenGL(ExtensionName multiviewExtension)
Martin Radev265a6d42017-09-12 16:51:37 +03002230{
Mingyu Huebab6702019-04-19 14:36:45 -07002231 return MultiviewRenderTestParams(0, VertexShaderOpenGL(3, 0, multiviewExtension));
Martin Radev265a6d42017-09-12 16:51:37 +03002232}
2233
Mingyu Huebab6702019-04-19 14:36:45 -07002234MultiviewRenderTestParams GeomShaderD3D11(ExtensionName multiviewExtension)
Martin Radev3c25ad02017-08-22 17:36:53 +03002235{
Mingyu Huebab6702019-04-19 14:36:45 -07002236 return MultiviewRenderTestParams(0, GeomShaderD3D11(3, 0, multiviewExtension));
Martin Radev3c25ad02017-08-22 17:36:53 +03002237}
2238
Mingyu Huebab6702019-04-19 14:36:45 -07002239MultiviewRenderTestParams VertexShaderD3D11(ExtensionName multiviewExtension)
Martin Radev3c25ad02017-08-22 17:36:53 +03002240{
Mingyu Huebab6702019-04-19 14:36:45 -07002241 return MultiviewRenderTestParams(0, VertexShaderD3D11(3, 0, multiviewExtension));
Martin Radev3c25ad02017-08-22 17:36:53 +03002242}
2243
Mingyu Huebab6702019-04-19 14:36:45 -07002244MultiviewRenderTestParams MultisampledVertexShaderOpenGL(ExtensionName multiviewExtension)
Martin Radev72b4e1e2017-08-31 15:42:56 +03002245{
Mingyu Huebab6702019-04-19 14:36:45 -07002246 return MultiviewRenderTestParams(2, VertexShaderOpenGL(3, 1, multiviewExtension));
Martin Radevc1d4e552017-08-21 12:01:10 +03002247}
2248
Mingyu Huebab6702019-04-19 14:36:45 -07002249MultiviewRenderTestParams MultisampledVertexShaderD3D11(ExtensionName multiviewExtension)
Martin Radevc1d4e552017-08-21 12:01:10 +03002250{
Mingyu Huebab6702019-04-19 14:36:45 -07002251 return MultiviewRenderTestParams(2, VertexShaderD3D11(3, 1, multiviewExtension));
Olli Etuaho2c8f0842018-09-12 14:44:55 +03002252}
2253
Jamie Madill04c084d2018-08-08 15:49:28 -04002254ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest,
Mingyu Huebab6702019-04-19 14:36:45 -07002255 VertexShaderOpenGL(3, 1, ExtensionName::multiview),
2256 VertexShaderD3D11(3, 1, ExtensionName::multiview),
2257 VertexShaderOpenGL(3, 1, ExtensionName::multiview2),
2258 VertexShaderD3D11(3, 1, ExtensionName::multiview2));
Martin Radevced5c862017-08-17 16:05:29 +03002259ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
Mingyu Huebab6702019-04-19 14:36:45 -07002260 VertexShaderOpenGL(ExtensionName::multiview),
2261 MultisampledVertexShaderOpenGL(ExtensionName::multiview),
2262 GeomShaderD3D11(ExtensionName::multiview),
2263 VertexShaderD3D11(ExtensionName::multiview),
2264 MultisampledVertexShaderD3D11(ExtensionName::multiview),
2265 VertexShaderOpenGL(ExtensionName::multiview2),
2266 MultisampledVertexShaderOpenGL(ExtensionName::multiview2),
2267 GeomShaderD3D11(ExtensionName::multiview2),
2268 VertexShaderD3D11(ExtensionName::multiview2),
2269 MultisampledVertexShaderD3D11(ExtensionName::multiview2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002270ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
Mingyu Huebab6702019-04-19 14:36:45 -07002271 VertexShaderOpenGL(ExtensionName::multiview),
2272 MultisampledVertexShaderOpenGL(ExtensionName::multiview),
2273 GeomShaderD3D11(ExtensionName::multiview),
2274 VertexShaderD3D11(ExtensionName::multiview),
2275 MultisampledVertexShaderD3D11(ExtensionName::multiview),
2276 VertexShaderOpenGL(ExtensionName::multiview2),
2277 MultisampledVertexShaderOpenGL(ExtensionName::multiview2),
2278 GeomShaderD3D11(ExtensionName::multiview2),
2279 VertexShaderD3D11(ExtensionName::multiview2),
2280 MultisampledVertexShaderD3D11(ExtensionName::multiview2));
Martin Radevced5c862017-08-17 16:05:29 +03002281ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
Mingyu Huebab6702019-04-19 14:36:45 -07002282 VertexShaderOpenGL(ExtensionName::multiview),
2283 GeomShaderD3D11(ExtensionName::multiview),
2284 VertexShaderD3D11(ExtensionName::multiview),
2285 VertexShaderOpenGL(ExtensionName::multiview2),
2286 GeomShaderD3D11(ExtensionName::multiview2),
2287 VertexShaderD3D11(ExtensionName::multiview2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03002288ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
Mingyu Huebab6702019-04-19 14:36:45 -07002289 VertexShaderOpenGL(3, 0, ExtensionName::multiview),
2290 GeomShaderD3D11(3, 0, ExtensionName::multiview),
2291 VertexShaderD3D11(3, 0, ExtensionName::multiview),
2292 VertexShaderOpenGL(3, 0, ExtensionName::multiview2),
2293 GeomShaderD3D11(3, 0, ExtensionName::multiview2),
2294 VertexShaderD3D11(3, 0, ExtensionName::multiview2));
Martin Radevced5c862017-08-17 16:05:29 +03002295ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
Mingyu Huebab6702019-04-19 14:36:45 -07002296 VertexShaderOpenGL(ExtensionName::multiview),
2297 GeomShaderD3D11(ExtensionName::multiview),
2298 VertexShaderD3D11(ExtensionName::multiview),
2299 VertexShaderOpenGL(ExtensionName::multiview2),
2300 GeomShaderD3D11(ExtensionName::multiview2),
2301 VertexShaderD3D11(ExtensionName::multiview2));
2302ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest,
2303 VertexShaderOpenGL(ExtensionName::multiview),
2304 GeomShaderD3D11(ExtensionName::multiview),
2305 VertexShaderOpenGL(ExtensionName::multiview2),
2306 GeomShaderD3D11(ExtensionName::multiview2));