blob: 073dc9344e7708f6fb93576039e8aa1d68c768a8 [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"
Martin Radev14a26ae2017-07-24 15:56:29 +030011#include "test_utils/ANGLETest.h"
12#include "test_utils/gl_raii.h"
13
14using namespace angle;
15
Martin Radev61bd9992017-08-11 13:10:55 +030016namespace
17{
Martin Radevced5c862017-08-17 16:05:29 +030018GLuint CreateSimplePassthroughProgram(int numViews)
Martin Radev61bd9992017-08-11 13:10:55 +030019{
20 const std::string vsSource =
21 "#version 300 es\n"
22 "#extension GL_OVR_multiview : require\n"
Martin Radevced5c862017-08-17 16:05:29 +030023 "layout(num_views = " +
24 ToString(numViews) +
25 ") in;\n"
Martin Radev61bd9992017-08-11 13:10:55 +030026 "layout(location=0) in vec2 vPosition;\n"
27 "void main()\n"
28 "{\n"
Martin Radevced5c862017-08-17 16:05:29 +030029 " gl_PointSize = 1.;\n"
Martin Radev61bd9992017-08-11 13:10:55 +030030 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
31 "}\n";
32
33 const std::string fsSource =
34 "#version 300 es\n"
35 "#extension GL_OVR_multiview : require\n"
36 "precision mediump float;\n"
37 "out vec4 col;\n"
38 "void main()\n"
39 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +030040 " col = vec4(0,1,0,1);\n"
Martin Radev61bd9992017-08-11 13:10:55 +030041 "}\n";
42 return CompileProgram(vsSource, fsSource);
43}
44
45std::vector<Vector2> ConvertPixelCoordinatesToClipSpace(const std::vector<Vector2I> &pixels,
46 int width,
47 int height)
48{
49 std::vector<Vector2> result(pixels.size());
50 for (size_t i = 0; i < pixels.size(); ++i)
51 {
52 const auto &pixel = pixels[i];
53 float pixelCenterRelativeX = (static_cast<float>(pixel.x()) + .5f) / width;
54 float pixelCenterRelativeY = (static_cast<float>(pixel.y()) + .5f) / height;
55 float xInClipSpace = 2.f * pixelCenterRelativeX - 1.f;
56 float yInClipSpace = 2.f * pixelCenterRelativeY - 1.f;
57 result[i] = Vector2(xInClipSpace, yInClipSpace);
58 }
59 return result;
60}
61} // namespace
62
Martin Radevc1d4e552017-08-21 12:01:10 +030063struct MultiviewImplementationParams : public PlatformParameters
Martin Radev3c25ad02017-08-22 17:36:53 +030064{
Martin Radevc1d4e552017-08-21 12:01:10 +030065 MultiviewImplementationParams(bool forceUseGeometryShaderOnD3D,
66 const EGLPlatformParameters &eglPlatformParameters)
67 : PlatformParameters(3, 0, eglPlatformParameters),
68 mForceUseGeometryShaderOnD3D(forceUseGeometryShaderOnD3D)
69 {
70 }
71 bool mForceUseGeometryShaderOnD3D;
72};
73
74std::ostream &operator<<(std::ostream &os, const MultiviewImplementationParams &params)
75{
76 const PlatformParameters &base = static_cast<const PlatformParameters &>(params);
77 os << base;
78 if (params.mForceUseGeometryShaderOnD3D)
79 {
80 os << "_force_geom_shader";
81 }
82 else
83 {
84 os << "_vertex_shader";
85 }
86 return os;
87}
88
89struct MultiviewTestParams final : public MultiviewImplementationParams
90{
91 MultiviewTestParams(GLenum multiviewLayout,
92 const MultiviewImplementationParams &implementationParams)
93 : MultiviewImplementationParams(implementationParams), mMultiviewLayout(multiviewLayout)
Martin Radev3c25ad02017-08-22 17:36:53 +030094 {
95 ASSERT(multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE ||
96 multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
97 }
98 GLenum mMultiviewLayout;
99};
100
101std::ostream &operator<<(std::ostream &os, const MultiviewTestParams &params)
102{
Martin Radevc1d4e552017-08-21 12:01:10 +0300103 const MultiviewImplementationParams &base =
104 static_cast<const MultiviewImplementationParams &>(params);
Martin Radev3c25ad02017-08-22 17:36:53 +0300105 os << base;
106 switch (params.mMultiviewLayout)
107 {
108 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
109 os << "_layered";
110 break;
111 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
112 os << "_side_by_side";
113 break;
114 default:
115 UNREACHABLE();
116 }
117 return os;
118}
119
120class MultiviewDrawTest : public ANGLETestBase
Martin Radev14a26ae2017-07-24 15:56:29 +0300121{
122 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300123 MultiviewDrawTest(const PlatformParameters &params) : ANGLETestBase(params)
Martin Radev14a26ae2017-07-24 15:56:29 +0300124 {
125 setWindowWidth(128);
126 setWindowHeight(128);
127 setWebGLCompatibilityEnabled(true);
128 }
Martin Radev7cf61662017-07-26 17:10:53 +0300129 virtual ~MultiviewDrawTest() {}
Martin Radev14a26ae2017-07-24 15:56:29 +0300130
Martin Radev3c25ad02017-08-22 17:36:53 +0300131 void DrawTestSetUp()
Martin Radev14a26ae2017-07-24 15:56:29 +0300132 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300133 ANGLETestBase::ANGLETestSetUp();
Martin Radev14a26ae2017-07-24 15:56:29 +0300134
135 glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
136 eglGetProcAddress("glRequestExtensionANGLE"));
137 }
138
139 // Requests the ANGLE_multiview extension and returns true if the operation succeeds.
140 bool requestMultiviewExtension()
141 {
142 if (extensionRequestable("GL_ANGLE_multiview"))
143 {
144 glRequestExtensionANGLE("GL_ANGLE_multiview");
145 }
146
147 if (!extensionEnabled("GL_ANGLE_multiview"))
148 {
149 std::cout << "Test skipped due to missing GL_ANGLE_multiview." << std::endl;
150 return false;
151 }
152 return true;
153 }
154
155 PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
156};
157
Martin Radev3c25ad02017-08-22 17:36:53 +0300158class MultiviewDrawValidationTest : public MultiviewDrawTest,
159 public ::testing::TestWithParam<PlatformParameters>
Martin Radev7cf61662017-07-26 17:10:53 +0300160{
161 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300162 MultiviewDrawValidationTest() : MultiviewDrawTest(GetParam()) {}
Martin Radev7cf61662017-07-26 17:10:53 +0300163
164 void SetUp() override
165 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300166 MultiviewDrawTest::DrawTestSetUp();
Martin Radev7cf61662017-07-26 17:10:53 +0300167
168 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
169
170 glBindTexture(GL_TEXTURE_2D, mTex2d);
171 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
172
173 glBindVertexArray(mVao);
174
175 const float kVertexData[3] = {0.0f};
176 glBindBuffer(GL_ARRAY_BUFFER, mVbo);
177 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
178
179 const unsigned int kIndices[3] = {0u, 1u, 2u};
180 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo);
181 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
182 GL_STATIC_DRAW);
183 ASSERT_GL_NO_ERROR();
184 }
185
186 GLTexture mTex2d;
187 GLVertexArray mVao;
188 GLBuffer mVbo;
189 GLBuffer mIbo;
190 GLFramebuffer mFramebuffer;
191};
192
Martin Radev3c25ad02017-08-22 17:36:53 +0300193class MultiviewRenderTestBase : public MultiviewDrawTest
Martin Radev8f276e22017-05-30 12:05:52 +0300194{
195 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300196 MultiviewRenderTestBase(const PlatformParameters &params, GLenum multiviewLayout)
197 : MultiviewDrawTest(params),
198 mMultiviewLayout(multiviewLayout),
199 mViewWidth(0),
200 mViewHeight(0),
201 mNumViews(0)
Martin Radev8f276e22017-05-30 12:05:52 +0300202 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300203 }
204 void RenderTestSetUp() { MultiviewDrawTest::DrawTestSetUp(); }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300205 void createFBO(int viewWidth, int height, int numViews, int numLayers, int baseViewIndex)
Martin Radev3c25ad02017-08-22 17:36:53 +0300206 {
Martin Radev72b4e1e2017-08-31 15:42:56 +0300207 ASSERT(numViews + baseViewIndex <= numLayers);
208
Martin Radev3c25ad02017-08-22 17:36:53 +0300209 mViewWidth = viewWidth;
210 mViewHeight = height;
211 mNumViews = numViews;
Martin Radev8f276e22017-05-30 12:05:52 +0300212
Martin Radev0abb7a22017-08-28 15:34:45 +0300213 mColorTexture.reset();
214 mDepthTexture.reset();
215 mDrawFramebuffer.reset();
216 mReadFramebuffer.clear();
217
Martin Radev8f276e22017-05-30 12:05:52 +0300218 // Create color and depth textures.
Martin Radev3c25ad02017-08-22 17:36:53 +0300219 switch (mMultiviewLayout)
Martin Radev8f276e22017-05-30 12:05:52 +0300220 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300221 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
222 {
223 int textureWidth = viewWidth * numViews;
224 glBindTexture(GL_TEXTURE_2D, mColorTexture);
225 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, height, 0, GL_RGBA,
226 GL_UNSIGNED_BYTE, NULL);
227 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
229
230 glBindTexture(GL_TEXTURE_2D, mDepthTexture);
231 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, textureWidth, height, 0,
232 GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
233 glBindTexture(GL_TEXTURE_2D, 0);
234 break;
235 }
236 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
237 glBindTexture(GL_TEXTURE_2D_ARRAY, mColorTexture);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300238 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, viewWidth, height, numLayers, 0,
Martin Radev3c25ad02017-08-22 17:36:53 +0300239 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
240 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
241 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
242
243 glBindTexture(GL_TEXTURE_2D_ARRAY, mDepthTexture);
244 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, viewWidth, height,
Martin Radev72b4e1e2017-08-31 15:42:56 +0300245 numLayers, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
Martin Radev3c25ad02017-08-22 17:36:53 +0300246 glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
247 break;
248 default:
249 UNREACHABLE();
Martin Radev8f276e22017-05-30 12:05:52 +0300250 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300251 ASSERT_GL_NO_ERROR();
252
253 // Create draw framebuffer to be used for multiview rendering.
254 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
255 switch (mMultiviewLayout)
256 {
257 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
258 {
259 std::vector<GLint> viewportOffsets(numViews * 2);
260 for (int i = 0u; i < numViews; ++i)
261 {
262 viewportOffsets[i * 2] = i * viewWidth;
263 viewportOffsets[i * 2 + 1] = 0;
264 }
265 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER,
266 GL_COLOR_ATTACHMENT0, mColorTexture, 0,
267 numViews, &viewportOffsets[0]);
268 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER,
269 GL_DEPTH_ATTACHMENT, mDepthTexture, 0,
270 numViews, &viewportOffsets[0]);
271 break;
272 }
273 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
274 glFramebufferTextureMultiviewLayeredANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
Martin Radev72b4e1e2017-08-31 15:42:56 +0300275 mColorTexture, 0, baseViewIndex,
276 numViews);
Martin Radev3c25ad02017-08-22 17:36:53 +0300277 glFramebufferTextureMultiviewLayeredANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
Martin Radev72b4e1e2017-08-31 15:42:56 +0300278 mDepthTexture, 0, baseViewIndex,
279 numViews);
Martin Radev3c25ad02017-08-22 17:36:53 +0300280 break;
281 default:
282 UNREACHABLE();
283 }
Martin Radev8f276e22017-05-30 12:05:52 +0300284
285 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
286 glDrawBuffers(1, DrawBuffers);
287 ASSERT_GL_NO_ERROR();
288 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
289
290 // Create read framebuffer to be used to retrieve the pixel information for testing
291 // purposes.
Martin Radev3c25ad02017-08-22 17:36:53 +0300292 switch (mMultiviewLayout)
293 {
294 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
295 mReadFramebuffer.resize(1);
296 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
297 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
298 mColorTexture, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300299 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
300 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300301 break;
302 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
Martin Radev72b4e1e2017-08-31 15:42:56 +0300303 mReadFramebuffer.resize(numLayers);
304 for (int i = 0; i < numLayers; ++i)
Martin Radev3c25ad02017-08-22 17:36:53 +0300305 {
Martin Radev72b4e1e2017-08-31 15:42:56 +0300306 glBindFramebuffer(GL_FRAMEBUFFER, mReadFramebuffer[i]);
307 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mColorTexture,
308 0, i);
309 glClearColor(0, 0, 0, 0);
310 glClear(GL_COLOR_BUFFER_BIT);
311 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
312 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300313 }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300314 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
Martin Radev3c25ad02017-08-22 17:36:53 +0300315 break;
316 default:
317 UNREACHABLE();
318 }
Martin Radev8f276e22017-05-30 12:05:52 +0300319
320 // Clear the buffers.
Martin Radev3c25ad02017-08-22 17:36:53 +0300321 glViewport(0, 0, viewWidth, height);
322 if (mMultiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
323 {
324 // Enable the scissor test only for side-by-side framebuffers.
325 glEnable(GL_SCISSOR_TEST);
326 glScissor(0, 0, viewWidth, height);
327 }
Martin Radev61bd9992017-08-11 13:10:55 +0300328 glClearColor(0, 0, 0, 1);
Martin Radev8f276e22017-05-30 12:05:52 +0300329 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev3c25ad02017-08-22 17:36:53 +0300330 }
Martin Radev8f276e22017-05-30 12:05:52 +0300331
Martin Radev72b4e1e2017-08-31 15:42:56 +0300332 void createFBO(int viewWidth, int height, int numViews)
333 {
334 createFBO(viewWidth, height, numViews, numViews, 0);
335 }
336
Martin Radev3c25ad02017-08-22 17:36:53 +0300337 GLColor GetViewColor(int x, int y, int view)
338 {
339 switch (mMultiviewLayout)
340 {
341 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
342 return ReadColor(view * mViewWidth + x, y);
343 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
344 ASSERT(static_cast<size_t>(view) < mReadFramebuffer.size());
345 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
346 return ReadColor(x, y);
347 default:
348 UNREACHABLE();
349 }
350 return GLColor(0, 0, 0, 0);
Martin Radev8f276e22017-05-30 12:05:52 +0300351 }
352
353 GLTexture mColorTexture;
354 GLTexture mDepthTexture;
355 GLFramebuffer mDrawFramebuffer;
Martin Radev3c25ad02017-08-22 17:36:53 +0300356 std::vector<GLFramebuffer> mReadFramebuffer;
357 GLenum mMultiviewLayout;
358 int mViewWidth;
359 int mViewHeight;
360 int mNumViews;
Martin Radev8f276e22017-05-30 12:05:52 +0300361};
362
Martin Radev3c25ad02017-08-22 17:36:53 +0300363class MultiviewRenderTest : public MultiviewRenderTestBase,
364 public ::testing::TestWithParam<MultiviewTestParams>
Martin Radev8f276e22017-05-30 12:05:52 +0300365{
366 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300367 MultiviewRenderTest() : MultiviewRenderTestBase(GetParam(), GetParam().mMultiviewLayout) {}
368 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
Martin Radevc1d4e552017-08-21 12:01:10 +0300369
370 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
371 {
372 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
373 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300374};
375
376class MultiviewRenderDualViewTest : public MultiviewRenderTest
377{
378 protected:
379 MultiviewRenderDualViewTest() : mProgram(0u) {}
380 ~MultiviewRenderDualViewTest()
Martin Radev8f276e22017-05-30 12:05:52 +0300381 {
382 if (mProgram != 0u)
383 {
384 glDeleteProgram(mProgram);
385 }
386 }
387
388 void SetUp() override
389 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300390 MultiviewRenderTest::SetUp();
Martin Radev8f276e22017-05-30 12:05:52 +0300391
392 if (!requestMultiviewExtension())
393 {
394 return;
395 }
396
397 const std::string vsSource =
398 "#version 300 es\n"
399 "#extension GL_OVR_multiview : require\n"
400 "layout(num_views = 2) in;\n"
401 "in vec4 vPosition;\n"
402 "void main()\n"
403 "{\n"
404 " gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x*0.5 + 0.5 : vPosition.x*0.5);\n"
405 " gl_Position.yzw = vPosition.yzw;\n"
406 "}\n";
407
408 const std::string fsSource =
409 "#version 300 es\n"
410 "#extension GL_OVR_multiview : require\n"
411 "precision mediump float;\n"
412 "out vec4 col;\n"
413 "void main()\n"
414 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300415 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300416 "}\n";
417
Martin Radev3c25ad02017-08-22 17:36:53 +0300418 createFBO(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +0300419 mProgram = CompileProgram(vsSource, fsSource);
420 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300421 glUseProgram(mProgram);
422 ASSERT_GL_NO_ERROR();
423 }
424
425 void checkOutput()
426 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300427 EXPECT_EQ(GLColor::black, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +0300428 EXPECT_EQ(GLColor::green, GetViewColor(1, 0, 0));
429 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +0300430 EXPECT_EQ(GLColor::black, GetViewColor(1, 0, 1));
Martin Radev8f276e22017-05-30 12:05:52 +0300431 }
432
433 GLuint mProgram;
434};
435
Martin Radev3c25ad02017-08-22 17:36:53 +0300436class MultiviewOcclusionQueryTest : public MultiviewRenderTest
Martin Radev0d671c92017-08-10 16:41:52 +0300437{
438 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300439 MultiviewOcclusionQueryTest() {}
Martin Radev0d671c92017-08-10 16:41:52 +0300440
441 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
442 {
443 GLuint query;
444 glGenQueries(1, &query);
445 glBeginQuery(GL_ANY_SAMPLES_PASSED, query);
446 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
447 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
448
449 GLuint result = GL_TRUE;
450 glGetQueryObjectuiv(query, GL_QUERY_RESULT, &result);
451 return result;
452 }
453};
454
Martin Radev3c25ad02017-08-22 17:36:53 +0300455class MultiviewProgramGenerationTest : public MultiviewRenderTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300456{
457 protected:
458 MultiviewProgramGenerationTest() {}
459};
460
Martin Radev3c25ad02017-08-22 17:36:53 +0300461class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300462{
463 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300464 MultiviewRenderPrimitiveTest() {}
Martin Radev61bd9992017-08-11 13:10:55 +0300465
466 void setupGeometry(const std::vector<Vector2> &vertexData)
467 {
Martin Radev61bd9992017-08-11 13:10:55 +0300468 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
469 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
470 GL_STATIC_DRAW);
471 glEnableVertexAttribArray(0);
472 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
473 }
474
Martin Radev67a8a012017-09-08 13:03:52 +0300475 void checkGreenChannel(const GLubyte expectedGreenChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300476 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300477 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300478 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300479 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300480 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300481 for (int h = 0; h < mViewHeight; ++h)
482 {
483 size_t flatIndex =
484 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
Martin Radev67a8a012017-09-08 13:03:52 +0300485 EXPECT_EQ(GLColor(0, expectedGreenChannelData[flatIndex], 0, 255),
Martin Radev3c25ad02017-08-22 17:36:53 +0300486 GetViewColor(w, h, view));
487 }
Martin Radev61bd9992017-08-11 13:10:55 +0300488 }
489 }
490 }
Martin Radev61bd9992017-08-11 13:10:55 +0300491 GLBuffer mVBO;
492};
493
Martin Radev3c25ad02017-08-22 17:36:53 +0300494class MultiviewSideBySideRenderTest : public MultiviewRenderTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300495 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev3c25ad02017-08-22 17:36:53 +0300496{
497 protected:
498 MultiviewSideBySideRenderTest()
499 : MultiviewRenderTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
500 {
501 }
502 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
Martin Radevc1d4e552017-08-21 12:01:10 +0300503 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
504 {
505 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
506 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300507};
508
Martin Radev72b4e1e2017-08-31 15:42:56 +0300509class MultiviewLayeredRenderTest : public MultiviewRenderTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300510 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev72b4e1e2017-08-31 15:42:56 +0300511{
512 protected:
513 MultiviewLayeredRenderTest()
514 : MultiviewRenderTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE)
515 {
516 }
517 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
Martin Radevc1d4e552017-08-21 12:01:10 +0300518 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
519 {
520 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
521 }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300522};
523
Martin Radev14a26ae2017-07-24 15:56:29 +0300524// The test verifies that glDraw*Indirect:
525// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
526// than 1.
527// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +0300528TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300529{
530 if (!requestMultiviewExtension())
531 {
532 return;
533 }
534
Martin Radev14a26ae2017-07-24 15:56:29 +0300535 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +0300536
537 const std::string fsSource =
538 "#version 300 es\n"
539 "#extension GL_OVR_multiview : require\n"
540 "precision mediump float;\n"
541 "void main()\n"
542 "{}\n";
543
Martin Radev14a26ae2017-07-24 15:56:29 +0300544 GLBuffer commandBuffer;
545 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
546 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
547 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
548 ASSERT_GL_NO_ERROR();
549
Martin Radev14a26ae2017-07-24 15:56:29 +0300550 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
551 {
552 const std::string &vsSource =
553 "#version 300 es\n"
554 "#extension GL_OVR_multiview : require\n"
555 "layout(num_views = 2) in;\n"
556 "void main()\n"
557 "{}\n";
558 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
559 glUseProgram(program);
560
Martin Radev7cf61662017-07-26 17:10:53 +0300561 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
562 0, 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300563
564 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
565 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
566
567 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
568 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
569 }
570
571 // Check that no errors are generated if the number of views is 1.
572 {
573 const std::string &vsSource =
574 "#version 300 es\n"
575 "#extension GL_OVR_multiview : require\n"
576 "layout(num_views = 1) in;\n"
577 "void main()\n"
578 "{}\n";
579 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
580 glUseProgram(program);
581
Martin Radev7cf61662017-07-26 17:10:53 +0300582 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
583 0, 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300584
585 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
586 EXPECT_GL_NO_ERROR();
587
588 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
589 EXPECT_GL_NO_ERROR();
590 }
591}
592
Martin Radev7cf61662017-07-26 17:10:53 +0300593// The test verifies that glDraw*:
594// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
595// program differs.
596// 2) does not generate any error if the number of views is the same.
Martin Radev7cf61662017-07-26 17:10:53 +0300597TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
598{
599 if (!requestMultiviewExtension())
600 {
601 return;
602 }
603
604 const GLint viewportOffsets[4] = {0, 0, 2, 0};
605
606 const std::string &vsSource =
607 "#version 300 es\n"
608 "#extension GL_OVR_multiview : require\n"
609 "layout(num_views = 2) in;\n"
610 "void main()\n"
611 "{}\n";
612 const std::string &fsSource =
613 "#version 300 es\n"
614 "#extension GL_OVR_multiview : require\n"
615 "precision mediump float;\n"
616 "void main()\n"
617 "{}\n";
618 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
619 glUseProgram(program);
620
621 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
622 // number of views.
623 {
624 // The framebuffer has only 1 view.
625 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
626 0, 1, &viewportOffsets[0]);
627
628 glDrawArrays(GL_TRIANGLES, 0, 3);
629 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
630
631 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
632 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
633 }
634
635 // Check that no errors are generated if the number of views in both program and draw
636 // framebuffer matches.
637 {
638 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
639 0, 2, &viewportOffsets[0]);
640
641 glDrawArrays(GL_TRIANGLES, 0, 3);
642 EXPECT_GL_NO_ERROR();
643
644 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
645 EXPECT_GL_NO_ERROR();
646 }
Martin Radevda8e2572017-09-12 17:21:16 +0300647}
Martin Radev7cf61662017-07-26 17:10:53 +0300648
Martin Radevda8e2572017-09-12 17:21:16 +0300649// The test verifies that glDraw* generates an INVALID_OPERATION error if the program does not use
650// the multiview extension, but the active draw framebuffer has more than one view.
651TEST_P(MultiviewDrawValidationTest, NumViewsMismatchForNonMultiviewProgram)
652{
653 if (!requestMultiviewExtension())
Martin Radev7cf61662017-07-26 17:10:53 +0300654 {
Martin Radevda8e2572017-09-12 17:21:16 +0300655 return;
Martin Radev7cf61662017-07-26 17:10:53 +0300656 }
Martin Radevda8e2572017-09-12 17:21:16 +0300657
658 const std::string &vsSourceNoMultiview =
659 "#version 300 es\n"
660 "void main()\n"
661 "{}\n";
662 const std::string &fsSourceNoMultiview =
663 "#version 300 es\n"
664 "precision mediump float;\n"
665 "void main()\n"
666 "{}\n";
667 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
668 glUseProgram(programNoMultiview);
669
670 const GLint viewportOffsets[4] = {0, 0, 2, 0};
671 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d, 0, 2,
672 &viewportOffsets[0]);
673
674 glDrawArrays(GL_TRIANGLES, 0, 3);
675 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
676
677 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
678 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radev7cf61662017-07-26 17:10:53 +0300679}
680
Martin Radev7e69f762017-07-27 14:54:13 +0300681// The test verifies that glDraw*:
682// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
683// greater than 1 and there is an active transform feedback object.
684// 2) does not generate any error if the number of views in the draw framebuffer is 1.
685TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
686{
687 if (!requestMultiviewExtension())
688 {
689 return;
690 }
691
692 const GLint viewportOffsets[4] = {0, 0, 2, 0};
693
694 const std::string &vsSource =
695 "#version 300 es\n"
696 "void main()\n"
697 "{}\n";
698 const std::string &fsSource =
699 "#version 300 es\n"
700 "precision mediump float;\n"
701 "void main()\n"
702 "{}\n";
703 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
704 glUseProgram(program);
705
706 GLBuffer tbo;
707 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
708 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4u, nullptr, GL_STATIC_DRAW);
709
710 GLTransformFeedback transformFeedback;
711 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
712 glBeginTransformFeedback(GL_TRIANGLES);
713 ASSERT_GL_NO_ERROR();
714
715 // Check that drawArrays generates an error when there is an active transform feedback object
716 // and the number of views in the draw framebuffer is greater than 1.
717 {
718 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
719 0, 2, &viewportOffsets[0]);
720 glDrawArrays(GL_TRIANGLES, 0, 3);
721 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
722 }
723
724 // Check that drawArrays does not generate an error when the number of views in the draw
725 // framebuffer is 1.
726 {
727 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
728 0, 1, &viewportOffsets[0]);
729 glDrawArrays(GL_TRIANGLES, 0, 3);
730 EXPECT_GL_NO_ERROR();
731 }
732
733 glEndTransformFeedback();
734}
735
Martin Radevffe754b2017-07-31 10:38:07 +0300736// The test verifies that glDraw*:
737// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
738// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
739// 2) does not generate any error if the number of views in the draw framebuffer is 1.
740TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
741{
742 if (!requestMultiviewExtension())
743 {
744 return;
745 }
746
747 if (!extensionEnabled("GL_EXT_disjoint_timer_query"))
748 {
749 std::cout << "Test skipped because GL_EXT_disjoint_timer_query is not available."
750 << std::endl;
751 return;
752 }
753
754 const GLint viewportOffsets[4] = {0, 0, 2, 0};
755 const std::string &vsSource =
756 "#version 300 es\n"
757 "void main()\n"
758 "{}\n";
759 const std::string &fsSource =
760 "#version 300 es\n"
761 "precision mediump float;\n"
762 "void main()\n"
763 "{}\n";
764 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
765 glUseProgram(program);
766
767 GLuint query = 0u;
768 glGenQueriesEXT(1, &query);
769 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
770
771 // Check first case.
772 {
773 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
774 0, 2, &viewportOffsets[0]);
775 glDrawArrays(GL_TRIANGLES, 0, 3);
776 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
777 }
778
779 // Check second case.
780 {
781 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
782 0, 1, &viewportOffsets[0]);
783 glDrawArrays(GL_TRIANGLES, 0, 3);
784 EXPECT_GL_NO_ERROR();
785 }
786
787 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
788 glDeleteQueries(1, &query);
789}
790
Martin Radev8f276e22017-05-30 12:05:52 +0300791// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300792TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300793{
794 if (!requestMultiviewExtension())
795 {
796 return;
797 }
798 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
799 ASSERT_GL_NO_ERROR();
800
801 checkOutput();
802}
803
804// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300805TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300806{
807 if (!requestMultiviewExtension())
808 {
809 return;
810 }
811 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
812 ASSERT_GL_NO_ERROR();
813
814 checkOutput();
815}
816
817// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300818TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300819{
820 if (!requestMultiviewExtension())
821 {
822 return;
823 }
824 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
825 ASSERT_GL_NO_ERROR();
826
827 checkOutput();
828}
829
830// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300831TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300832{
833 if (!requestMultiviewExtension())
834 {
835 return;
836 }
837
838 const std::string vsSource =
839 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300840 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300841 "layout(num_views = 4) in;\n"
842 "in vec4 vPosition;\n"
843 "void main()\n"
844 "{\n"
845 " if (gl_ViewID_OVR == 0u) {\n"
846 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
847 " } else if (gl_ViewID_OVR == 1u) {\n"
848 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
849 " } else if (gl_ViewID_OVR == 2u) {\n"
850 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
851 " } else {\n"
852 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
853 " }"
854 " gl_Position.yzw = vPosition.yzw;\n"
855 "}\n";
856
857 const std::string fsSource =
858 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300859 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300860 "precision mediump float;\n"
861 "out vec4 col;\n"
862 "void main()\n"
863 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300864 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300865 "}\n";
866
Martin Radev3c25ad02017-08-22 17:36:53 +0300867 createFBO(4, 1, 4);
Martin Radev8f276e22017-05-30 12:05:52 +0300868 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +0300869
870 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
871 ASSERT_GL_NO_ERROR();
872
873 for (int i = 0; i < 4; ++i)
874 {
875 for (int j = 0; j < 4; ++j)
876 {
Martin Radev8f276e22017-05-30 12:05:52 +0300877 if (i == j)
878 {
Martin Radev67a8a012017-09-08 13:03:52 +0300879 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300880 }
881 else
882 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300883 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300884 }
885 }
886 }
887 EXPECT_GL_NO_ERROR();
888}
889
890// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300891TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +0300892{
893 if (!requestMultiviewExtension())
894 {
895 return;
896 }
897
898 const std::string vsSource =
899 "#version 300 es\n"
900 "#extension GL_OVR_multiview : require\n"
901 "layout(num_views = 2) in;\n"
902 "in vec4 vPosition;\n"
903 "void main()\n"
904 "{\n"
905 " vec4 p = vPosition;\n"
906 " if (gl_InstanceID == 1){\n"
907 " p.y = .5*p.y + .5;\n"
908 " } else {\n"
909 " p.y = p.y*.5;\n"
910 " }\n"
911 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x*0.5 + 0.5 : p.x*0.5);\n"
912 " gl_Position.yzw = p.yzw;\n"
913 "}\n";
914
915 const std::string fsSource =
916 "#version 300 es\n"
917 "#extension GL_OVR_multiview : require\n"
918 "precision mediump float;\n"
919 "out vec4 col;\n"
920 "void main()\n"
921 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300922 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300923 "}\n";
924
Martin Radev3c25ad02017-08-22 17:36:53 +0300925 const int kViewWidth = 2;
926 const int kViewHeight = 2;
927 const int kNumViews = 2;
928 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev8f276e22017-05-30 12:05:52 +0300929 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +0300930
Martin Radev67a8a012017-09-08 13:03:52 +0300931 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 2u);
Martin Radev8f276e22017-05-30 12:05:52 +0300932 ASSERT_GL_NO_ERROR();
933
Martin Radev67a8a012017-09-08 13:03:52 +0300934 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
935 {{255, 0}, {255, 0}}};
Martin Radev3c25ad02017-08-22 17:36:53 +0300936
937 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +0300938 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300939 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +0300940 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300941 for (int x = 0; x < 2; ++x)
942 {
Martin Radev67a8a012017-09-08 13:03:52 +0300943 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][y][x], 0, 255),
Martin Radev3c25ad02017-08-22 17:36:53 +0300944 GetViewColor(x, y, view));
945 }
Martin Radev8f276e22017-05-30 12:05:52 +0300946 }
947 }
948}
949
Martin Radev553590a2017-07-31 16:40:39 +0300950// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
951// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
952// offset of each quad are passed as separate attributes which are indexed based on the
953// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
954// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
955// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
956// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +0300957TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +0300958{
959 if (!requestMultiviewExtension())
960 {
961 return;
962 }
963
964 const std::string &vsSource =
965 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300966 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +0300967 "layout(num_views = 2) in;\n"
968 "in vec3 vPosition;\n"
969 "in float offsetX;\n"
970 "in float offsetY;\n"
971 "void main()\n"
972 "{\n"
973 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +0300974 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300975 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
976 " gl_Position.yzw = p.yzw;\n"
977 "}\n";
978
979 const std::string &fsSource =
980 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300981 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +0300982 "precision mediump float;\n"
983 "out vec4 col;\n"
984 "void main()\n"
985 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300986 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300987 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +0300988
989 const int kViewWidth = 4;
990 const int kViewHeight = 4;
991 const int kNumViews = 2;
992 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev553590a2017-07-31 16:40:39 +0300993 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev553590a2017-07-31 16:40:39 +0300994
995 GLBuffer xOffsetVBO;
996 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
997 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
998 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
999 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1000 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1001 glVertexAttribDivisor(xOffsetLoc, 3);
1002 glEnableVertexAttribArray(xOffsetLoc);
1003
1004 GLBuffer yOffsetVBO;
1005 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1006 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1007 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1008 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1009 glVertexAttribDivisor(yOffsetLoc, 1);
1010 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1011 glEnableVertexAttribArray(yOffsetLoc);
1012
Martin Radev67a8a012017-09-08 13:03:52 +03001013 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev553590a2017-07-31 16:40:39 +03001014 ASSERT_GL_NO_ERROR();
1015
Martin Radev67a8a012017-09-08 13:03:52 +03001016 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001017 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1018 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1019 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +03001020 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001021 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +03001022 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001023 for (int col = 0; col < 4; ++col)
1024 {
Martin Radev67a8a012017-09-08 13:03:52 +03001025 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0, 255),
Martin Radev3c25ad02017-08-22 17:36:53 +03001026 GetViewColor(col, row, view));
1027 }
Martin Radev553590a2017-07-31 16:40:39 +03001028 }
1029 }
1030}
1031
1032// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1033// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +03001034TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +03001035{
1036 if (!requestMultiviewExtension())
1037 {
1038 return;
1039 }
1040
Martin Radev3c25ad02017-08-22 17:36:53 +03001041 createFBO(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +03001042
1043 // Create multiview program.
1044 const std::string &vs =
1045 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001046 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001047 "layout(num_views = 2) in;\n"
1048 "layout(location = 0) in vec2 vPosition;\n"
1049 "layout(location = 1) in float offsetX;\n"
1050 "void main()\n"
1051 "{\n"
1052 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1053 " p.x += offsetX;\n"
1054 " gl_Position = p;\n"
1055 "}\n";
1056
1057 const std::string &fs =
1058 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001059 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001060 "precision mediump float;\n"
1061 "out vec4 col;\n"
1062 "void main()\n"
1063 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001064 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001065 "}\n";
1066
1067 ANGLE_GL_PROGRAM(program, vs, fs);
1068
1069 const std::string &dummyVS =
1070 "#version 300 es\n"
1071 "layout(location = 0) in vec2 vPosition;\n"
1072 "layout(location = 1) in float offsetX;\n"
1073 "void main()\n"
1074 "{\n"
1075 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1076 "}\n";
1077
1078 const std::string &dummyFS =
1079 "#version 300 es\n"
1080 "precision mediump float;\n"
1081 "out vec4 col;\n"
1082 "void main()\n"
1083 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001084 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001085 "}\n";
1086
1087 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
1088
1089 GLBuffer xOffsetVBO;
1090 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1091 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1092 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1093 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1094
1095 GLBuffer vertexVBO;
1096 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1097 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1098 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1099 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1100
1101 GLVertexArray vao[2];
1102 for (size_t i = 0u; i < 2u; ++i)
1103 {
1104 glBindVertexArray(vao[i]);
1105
1106 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1107 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1108 glEnableVertexAttribArray(0);
1109
1110 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1111 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1112 glEnableVertexAttribArray(1);
1113 }
1114 ASSERT_GL_NO_ERROR();
1115
1116 glViewport(0, 0, 1, 1);
1117 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001118 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001119 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001120
1121 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1122 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1123 // bits are cleared.
1124 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001125 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1126 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001127 glBindVertexArray(vao[0]);
1128 glVertexAttribDivisor(1, 0);
1129 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1130 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001131 ASSERT_GL_NO_ERROR();
1132
1133 // Check that vertexAttribDivisor uses the number of views to update the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001134 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
1135 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001136 glUseProgram(program);
1137 glVertexAttribDivisor(1, 1);
1138 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001139 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1140 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001141
1142 // Clear the buffers and propagate divisor to the driver.
1143 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1144 // dirty bits when useProgram is called.
1145 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001146 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1147 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001148 glVertexAttribDivisor(1, 1);
1149 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1150 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001151 ASSERT_GL_NO_ERROR();
1152
1153 // Check that useProgram uses the number of views to update the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001154 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
1155 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001156 glUseProgram(program);
1157 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001158 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1159 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001160
1161 // We go through similar steps as before.
1162 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001163 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1164 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001165 glVertexAttribDivisor(1, 1);
1166 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1167 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001168 ASSERT_GL_NO_ERROR();
1169
1170 // Check that bindVertexArray uses the number of views to update the divisor.
1171 {
1172 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1173 // divisor for vao[1] only.
Martin Radevda8e2572017-09-12 17:21:16 +03001174 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
1175 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001176 glBindVertexArray(vao[1]);
1177 glUseProgram(program);
1178 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001179 glBindVertexArray(0);
1180 ASSERT_GL_NO_ERROR();
1181 }
1182 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1183 // adjusts the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001184 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001185 glBindVertexArray(vao[0]);
1186 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001187 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1188 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001189}
1190
Martin Radev0d671c92017-08-10 16:41:52 +03001191// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1192// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001193TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001194{
1195 if (!requestMultiviewExtension())
1196 {
1197 return;
1198 }
1199
1200 const std::string vsSource =
1201 "#version 300 es\n"
1202 "#extension GL_OVR_multiview : require\n"
1203 "layout(num_views = 2) in;\n"
1204 "in vec3 vPosition;\n"
1205 "void main()\n"
1206 "{\n"
1207 " gl_Position.x = 2.0;\n"
1208 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1209 "}\n";
1210
1211 const std::string fsSource =
1212 "#version 300 es\n"
1213 "#extension GL_OVR_multiview : require\n"
1214 "precision mediump float;\n"
1215 "out vec4 col;\n"
1216 "void main()\n"
1217 "{\n"
1218 " col = vec4(1,0,0,0);\n"
1219 "}\n";
1220 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev3c25ad02017-08-22 17:36:53 +03001221 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001222
1223 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1224 ASSERT_GL_NO_ERROR();
1225 EXPECT_GL_FALSE(result);
1226}
1227
1228// Test that there are fragments passing the occlusion query if only view 0 can produce
1229// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001230TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001231{
1232 if (!requestMultiviewExtension())
1233 {
1234 return;
1235 }
1236
1237 const std::string vsSource =
1238 "#version 300 es\n"
1239 "#extension GL_OVR_multiview : require\n"
1240 "layout(num_views = 2) in;\n"
1241 "in vec3 vPosition;\n"
1242 "void main()\n"
1243 "{\n"
1244 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1245 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1246 "}\n";
1247
1248 const std::string fsSource =
1249 "#version 300 es\n"
1250 "#extension GL_OVR_multiview : require\n"
1251 "precision mediump float;\n"
1252 "out vec4 col;\n"
1253 "void main()\n"
1254 "{\n"
1255 " col = vec4(1,0,0,0);\n"
1256 "}\n";
1257 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev3c25ad02017-08-22 17:36:53 +03001258 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001259
1260 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1261 ASSERT_GL_NO_ERROR();
1262 EXPECT_GL_TRUE(result);
1263}
1264
1265// Test that there are fragments passing the occlusion query if only view 1 can produce
1266// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001267TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001268{
1269 if (!requestMultiviewExtension())
1270 {
1271 return;
1272 }
1273
1274 const std::string vsSource =
1275 "#version 300 es\n"
1276 "#extension GL_OVR_multiview : require\n"
1277 "layout(num_views = 2) in;\n"
1278 "in vec3 vPosition;\n"
1279 "void main()\n"
1280 "{\n"
1281 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1282 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1283 "}\n";
1284
1285 const std::string fsSource =
1286 "#version 300 es\n"
1287 "#extension GL_OVR_multiview : require\n"
1288 "precision mediump float;\n"
1289 "out vec4 col;\n"
1290 "void main()\n"
1291 "{\n"
1292 " col = vec4(1,0,0,0);\n"
1293 "}\n";
1294 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev3c25ad02017-08-22 17:36:53 +03001295 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001296
1297 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1298 ASSERT_GL_NO_ERROR();
1299 EXPECT_GL_TRUE(result);
1300}
1301
Martin Radev41ac68e2017-06-06 12:16:58 +03001302// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1303// compiles and links without an error.
1304TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1305{
1306 if (!requestMultiviewExtension())
1307 {
1308 return;
1309 }
1310
1311 const std::string vsSource =
1312 "#version 300 es\n"
1313 "#extension GL_OVR_multiview : require\n"
1314 "layout(num_views = 2) in;\n"
1315 "void main()\n"
1316 "{\n"
1317 "}\n";
1318
1319 const std::string fsSource =
1320 "#version 300 es\n"
1321 "#extension GL_OVR_multiview : require\n"
1322 "precision mediump float;\n"
1323 "void main()\n"
1324 "{\n"
1325 "}\n";
1326
1327 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1328 glUseProgram(program);
1329
1330 EXPECT_GL_NO_ERROR();
1331}
1332
1333// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1334// without an error.
1335TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1336{
1337 if (!requestMultiviewExtension())
1338 {
1339 return;
1340 }
1341
1342 const std::string vsSource =
1343 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001344 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001345 "layout(num_views = 2) in;\n"
1346 "void main()\n"
1347 "{\n"
1348 " if (gl_ViewID_OVR == 0u) {\n"
1349 " gl_Position = vec4(1,0,0,1);\n"
1350 " } else {\n"
1351 " gl_Position = vec4(-1,0,0,1);\n"
1352 " }\n"
1353 "}\n";
1354
1355 const std::string fsSource =
1356 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001357 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001358 "precision mediump float;\n"
1359 "void main()\n"
1360 "{\n"
1361 "}\n";
1362
1363 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1364 glUseProgram(program);
1365
1366 EXPECT_GL_NO_ERROR();
1367}
1368
1369// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1370// without an error.
1371TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1372{
1373 if (!requestMultiviewExtension())
1374 {
1375 return;
1376 }
1377
1378 const std::string vsSource =
1379 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001380 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001381 "layout(num_views = 2) in;\n"
1382 "void main()\n"
1383 "{\n"
1384 "}\n";
1385
1386 const std::string fsSource =
1387 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001388 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001389 "precision mediump float;\n"
1390 "out vec4 col;\n"
1391 "void main()\n"
1392 "{\n"
1393 " if (gl_ViewID_OVR == 0u) {\n"
1394 " col = vec4(1,0,0,1);\n"
1395 " } else {\n"
1396 " col = vec4(-1,0,0,1);\n"
1397 " }\n"
1398 "}\n";
1399
1400 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1401 glUseProgram(program);
1402
1403 EXPECT_GL_NO_ERROR();
1404}
1405
Martin Radev61bd9992017-08-11 13:10:55 +03001406// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001407TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001408{
1409 if (!requestMultiviewExtension())
1410 {
1411 return;
1412 }
1413
1414 const std::string vsSource =
1415 "#version 300 es\n"
1416 "#extension GL_OVR_multiview : require\n"
1417 "layout(num_views = 2) in;\n"
1418 "layout(location=0) in vec2 vPosition;\n"
1419 "void main()\n"
1420 "{\n"
1421 " gl_PointSize = 1.0;\n"
1422 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1423 "}\n";
1424
1425 const std::string fsSource =
1426 "#version 300 es\n"
1427 "#extension GL_OVR_multiview : require\n"
1428 "precision mediump float;\n"
1429 "out vec4 col;\n"
1430 "void main()\n"
1431 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001432 " col = vec4(0,1,0,1);\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001433 "}\n";
1434 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1435 glUseProgram(program);
1436
Martin Radev3c25ad02017-08-22 17:36:53 +03001437 const int kViewWidth = 4;
1438 const int kViewHeight = 2;
1439 const int kNumViews = 2;
1440 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001441
1442 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1443 std::vector<Vector2> vertexDataInClipSpace =
1444 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1445 setupGeometry(vertexDataInClipSpace);
1446
1447 glDrawArrays(GL_POINTS, 0, 2);
1448
Martin Radev67a8a012017-09-08 13:03:52 +03001449 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001450 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001451 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001452}
1453
1454// The test checks that GL_LINES is correctly rendered.
1455// The behavior of this test is not guaranteed by the spec:
1456// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1457// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1458// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1459// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001460TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001461{
1462 if (!requestMultiviewExtension())
1463 {
1464 return;
1465 }
1466
Martin Radevced5c862017-08-17 16:05:29 +03001467 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001468 ASSERT_NE(program, 0u);
1469 glUseProgram(program);
1470 ASSERT_GL_NO_ERROR();
1471
Martin Radev3c25ad02017-08-22 17:36:53 +03001472 const int kViewWidth = 4;
1473 const int kViewHeight = 2;
1474 const int kNumViews = 2;
1475 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001476
1477 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1478 std::vector<Vector2> vertexDataInClipSpace =
1479 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1480 setupGeometry(vertexDataInClipSpace);
1481
1482 glDrawArrays(GL_LINES, 0, 2);
1483
Martin Radev67a8a012017-09-08 13:03:52 +03001484 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001485 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001486 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001487
1488 glDeleteProgram(program);
1489}
1490
1491// The test checks that GL_LINE_STRIP is correctly rendered.
1492// The behavior of this test is not guaranteed by the spec:
1493// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1494// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1495// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1496// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001497TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001498{
1499 if (!requestMultiviewExtension())
1500 {
1501 return;
1502 }
1503
Martin Radevced5c862017-08-17 16:05:29 +03001504 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001505 ASSERT_NE(program, 0u);
1506 glUseProgram(program);
1507 ASSERT_GL_NO_ERROR();
1508
Martin Radev3c25ad02017-08-22 17:36:53 +03001509 const int kViewWidth = 4;
1510 const int kViewHeight = 2;
1511 const int kNumViews = 2;
1512 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001513
1514 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1515 std::vector<Vector2> vertexDataInClipSpace =
1516 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1517 setupGeometry(vertexDataInClipSpace);
1518
1519 glDrawArrays(GL_LINE_STRIP, 0, 3);
1520
Martin Radev67a8a012017-09-08 13:03:52 +03001521 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001522 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001523 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001524
1525 glDeleteProgram(program);
1526}
1527
1528// The test checks that GL_LINE_LOOP is correctly rendered.
1529// The behavior of this test is not guaranteed by the spec:
1530// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1531// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1532// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1533// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001534TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001535{
1536 if (!requestMultiviewExtension())
1537 {
1538 return;
1539 }
1540
Martin Radevced5c862017-08-17 16:05:29 +03001541 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001542 ASSERT_NE(program, 0u);
1543 glUseProgram(program);
1544 ASSERT_GL_NO_ERROR();
1545
Martin Radev3c25ad02017-08-22 17:36:53 +03001546 const int kViewWidth = 4;
1547 const int kViewHeight = 4;
1548 const int kNumViews = 2;
1549 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001550
1551 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1552 Vector2I(0, 3)};
1553 std::vector<Vector2> vertexDataInClipSpace =
1554 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1555 setupGeometry(vertexDataInClipSpace);
1556
1557 glDrawArrays(GL_LINE_LOOP, 0, 4);
1558
Martin Radev67a8a012017-09-08 13:03:52 +03001559 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001560 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1561 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001562 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001563
1564 glDeleteProgram(program);
1565}
1566
1567// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001568TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001569{
1570 if (!requestMultiviewExtension())
1571 {
1572 return;
1573 }
1574
Martin Radevced5c862017-08-17 16:05:29 +03001575 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001576 ASSERT_NE(program, 0u);
1577 glUseProgram(program);
1578 ASSERT_GL_NO_ERROR();
1579
1580 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1581 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1582 setupGeometry(vertexDataInClipSpace);
1583
Martin Radev3c25ad02017-08-22 17:36:53 +03001584 const int kViewWidth = 2;
1585 const int kViewHeight = 2;
1586 const int kNumViews = 2;
1587 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001588
1589 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1590
Martin Radev67a8a012017-09-08 13:03:52 +03001591 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1592 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1593 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001594
1595 glDeleteProgram(program);
1596}
1597
1598// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001599TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001600{
1601 if (!requestMultiviewExtension())
1602 {
1603 return;
1604 }
1605
Martin Radevced5c862017-08-17 16:05:29 +03001606 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001607 ASSERT_NE(program, 0u);
1608 glUseProgram(program);
1609 ASSERT_GL_NO_ERROR();
1610
1611 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1612 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1613 setupGeometry(vertexDataInClipSpace);
1614
Martin Radev3c25ad02017-08-22 17:36:53 +03001615 const int kViewWidth = 2;
1616 const int kViewHeight = 2;
1617 const int kNumViews = 2;
1618 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001619
1620 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1621
Martin Radev67a8a012017-09-08 13:03:52 +03001622 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1623 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1624 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001625
1626 glDeleteProgram(program);
1627}
1628
1629// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1630// bounds. The test does not rely on the actual line width being greater than 1.0.
Martin Radev3c25ad02017-08-22 17:36:53 +03001631TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
Martin Radev61bd9992017-08-11 13:10:55 +03001632{
1633 if (!requestMultiviewExtension())
1634 {
1635 return;
1636 }
1637
Martin Radev3c25ad02017-08-22 17:36:53 +03001638 createFBO(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +03001639
1640 GLint viewportOffsets[4] = {1, 0, 3, 0};
1641 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1642 mColorTexture, 0, 2, &viewportOffsets[0]);
1643 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
1644 mDepthTexture, 0, 2, &viewportOffsets[0]);
1645
1646 glViewport(0, 0, 1, 1);
1647 glScissor(0, 0, 1, 1);
1648 glEnable(GL_SCISSOR_TEST);
1649
1650 const std::string vsSource =
1651 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001652 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001653 "layout(num_views = 2) in;\n"
1654 "layout(location=0) in vec2 vPosition;\n"
1655 "void main()\n"
1656 "{\n"
1657 " gl_PointSize = 10.0;\n"
1658 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1659 "}\n";
1660
1661 const std::string fsSource =
1662 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001663 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001664 "precision mediump float;\n"
1665 "out vec4 col;\n"
1666 "void main()\n"
1667 "{\n"
1668 " if (gl_ViewID_OVR == 0u) {\n"
1669 " col = vec4(1,0,0,1);\n"
1670 " } else {\n"
1671 " col = vec4(0,1,0,1);\n"
1672 " }\n"
1673 "}\n";
1674 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1675 glUseProgram(program);
1676
1677 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1678 const std::vector<Vector2> &vertexDataInClipSpace =
1679 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001680
1681 GLBuffer vbo;
1682 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1683 glBufferData(GL_ARRAY_BUFFER, vertexDataInClipSpace.size() * sizeof(Vector2),
1684 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1685 glEnableVertexAttribArray(0);
1686 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
Martin Radev61bd9992017-08-11 13:10:55 +03001687
1688 // Test rendering points.
1689 {
1690 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1691 glDrawArrays(GL_POINTS, 0, 2);
1692 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1693 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1694 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1695 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1696 }
1697
1698 // Test rendering lines.
1699 {
1700 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1701 glLineWidth(10.f);
1702 glDrawArrays(GL_LINES, 0, 2);
1703 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1704 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1705 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1706 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1707 }
1708}
1709
Martin Radev0abb7a22017-08-28 15:34:45 +03001710// Verify that re-linking a program adjusts the attribute divisor.
1711// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1712// to each other. The quads' position and color depend on the corresponding attribute divisors.
1713TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1714{
1715 if (!requestMultiviewExtension())
1716 {
1717 return;
1718 }
1719
1720 const int kViewWidth = 4;
1721 const int kViewHeight = 1;
1722 const int kNumViews = 2;
1723
1724 const std::string &fsSource =
1725 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001726 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001727 "precision mediump float;\n"
1728 "in vec4 oColor;\n"
1729 "out vec4 col;\n"
1730 "void main()\n"
1731 "{\n"
1732 " col = oColor;\n"
1733 "}\n";
1734
1735 auto generateVertexShaderSource = [](int numViews) -> std::string {
1736 std::string source =
1737 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001738 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001739 "layout(num_views = " +
1740 ToString(numViews) +
1741 ") in;\n"
1742 "in vec3 vPosition;\n"
1743 "in float vOffsetX;\n"
1744 "in vec4 vColor;\n"
1745 "out vec4 oColor;\n"
1746 "void main()\n"
1747 "{\n"
1748 " vec4 p = vec4(vPosition, 1.);\n"
1749 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1750 " oColor = vColor;\n"
1751 " gl_Position = p;\n"
1752 "}\n";
1753 return source;
1754 };
1755
1756 std::string vsSource = generateVertexShaderSource(kNumViews);
1757 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1758 glUseProgram(program);
1759
1760 GLint positionLoc;
1761 GLBuffer xOffsetVBO;
1762 GLint xOffsetLoc;
1763 GLBuffer colorVBO;
1764 GLint colorLoc;
1765
1766 {
1767 // Initialize buffers and setup attributes.
1768 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1769 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1770 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1771 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1772 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1773 glVertexAttribDivisor(xOffsetLoc, 1);
1774 glEnableVertexAttribArray(xOffsetLoc);
1775
1776 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1777 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1778 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1779 colorLoc = glGetAttribLocation(program, "vColor");
1780 glVertexAttribDivisor(colorLoc, 2);
1781 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1782 glEnableVertexAttribArray(colorLoc);
1783
1784 positionLoc = glGetAttribLocation(program, "vPosition");
1785 }
1786
1787 {
1788 createFBO(kViewWidth, kViewHeight, kNumViews);
1789
Martin Radev67a8a012017-09-08 13:03:52 +03001790 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001791 ASSERT_GL_NO_ERROR();
1792
1793 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1794 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1795 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1796 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1797 }
1798
1799 {
1800 const int kNewNumViews = 3;
1801 vsSource = generateVertexShaderSource(kNewNumViews);
1802 createFBO(kViewWidth, kViewHeight, kNewNumViews);
1803
1804 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
1805 ASSERT_NE(0u, vs);
1806 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
1807 ASSERT_NE(0u, fs);
1808
1809 GLint numAttachedShaders = 0;
1810 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1811
1812 GLuint attachedShaders[2] = {0u};
1813 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1814 for (int i = 0; i < 2; ++i)
1815 {
1816 glDetachShader(program, attachedShaders[i]);
1817 }
1818
1819 glAttachShader(program, vs);
1820 glDeleteShader(vs);
1821
1822 glAttachShader(program, fs);
1823 glDeleteShader(fs);
1824
1825 glBindAttribLocation(program, positionLoc, "vPosition");
1826 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1827 glBindAttribLocation(program, colorLoc, "vColor");
1828
1829 glLinkProgram(program);
1830
Martin Radev67a8a012017-09-08 13:03:52 +03001831 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001832 ASSERT_GL_NO_ERROR();
1833
1834 for (int i = 0; i < kNewNumViews; ++i)
1835 {
1836 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1837 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1838 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1839 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1840 }
1841 }
1842}
1843
Martin Radevced5c862017-08-17 16:05:29 +03001844// Test that useProgram applies the number of views in computing the final value of the attribute
1845// divisor.
1846TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1847{
1848 if (!requestMultiviewExtension())
1849 {
1850 return;
1851 }
1852
1853 GLVertexArray vao;
1854 glBindVertexArray(vao);
1855 GLBuffer vbo;
1856 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1857 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
1858 Vector2I(3, 0)};
1859 std::vector<Vector2> vertexDataInClipSpace =
1860 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
1861 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
1862 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
1863 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1864 glEnableVertexAttribArray(0);
1865 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
1866 glVertexAttribDivisor(0, 1);
1867 ASSERT_GL_NO_ERROR();
1868
1869 // Create a program and fbo with N views and draw N instances of a point horizontally.
1870 for (int numViews = 2; numViews <= 4; ++numViews)
1871 {
1872 createFBO(4, 1, numViews);
1873 ASSERT_GL_NO_ERROR();
1874
1875 GLuint program = CreateSimplePassthroughProgram(numViews);
1876 ASSERT_NE(program, 0u);
1877 glUseProgram(program);
1878 ASSERT_GL_NO_ERROR();
1879
1880 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
1881
1882 for (int view = 0; view < numViews; ++view)
1883 {
1884 for (int j = 0; j < numViews; ++j)
1885 {
Martin Radev67a8a012017-09-08 13:03:52 +03001886 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03001887 }
1888 for (int j = numViews; j < 4; ++j)
1889 {
1890 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, view));
1891 }
1892 }
1893
1894 glDeleteProgram(program);
1895 }
1896}
1897
Martin Radev72b4e1e2017-08-31 15:42:56 +03001898// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
1899TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
1900{
1901 if (!requestMultiviewExtension())
1902 {
1903 return;
1904 }
1905
1906 const std::string vsSource =
1907 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001908 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001909 "layout(num_views = 3) in;\n"
1910 "in vec3 vPosition;\n"
1911 "void main()\n"
1912 "{\n"
1913 " gl_Position = vec4(vPosition, 1.);\n"
1914 "}\n";
1915
1916 const std::string fsSource =
1917 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001918 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001919 "precision mediump float;\n"
1920 "out vec4 col;\n"
1921 "void main()\n"
1922 "{\n"
1923 " if (gl_ViewID_OVR == 0u) {\n"
1924 " col = vec4(1,0,0,1);\n"
1925 " } else if (gl_ViewID_OVR == 1u) {\n"
1926 " col = vec4(0,1,0,1);\n"
1927 " } else if (gl_ViewID_OVR == 2u) {\n"
1928 " col = vec4(0,0,1,1);\n"
1929 " } else {\n"
1930 " col = vec4(0,0,0,0);\n"
1931 " }\n"
1932 "}\n";
1933
1934 createFBO(1, 1, 3);
1935 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03001936
1937 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1938 ASSERT_GL_NO_ERROR();
1939
1940 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1941 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1942 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
1943}
1944
1945// The test checks that the inactive layers of a 2D texture array are not written to by a
1946// multi-view program.
1947TEST_P(MultiviewLayeredRenderTest, RenderToSubrageOfLayers)
1948{
1949 if (!requestMultiviewExtension())
1950 {
1951 return;
1952 }
1953
1954 const std::string vsSource =
1955 "#version 300 es\n"
1956 "#extension GL_OVR_multiview : require\n"
1957 "layout(num_views = 2) in;\n"
1958 "in vec3 vPosition;\n"
1959 "void main()\n"
1960 "{\n"
1961 " gl_Position = vec4(vPosition, 1.);\n"
1962 "}\n";
1963
1964 const std::string fsSource =
1965 "#version 300 es\n"
1966 "#extension GL_OVR_multiview : require\n"
1967 "precision mediump float;\n"
1968 "out vec4 col;\n"
1969 "void main()\n"
1970 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001971 " col = vec4(0,1,0,1);\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001972 "}\n";
1973
1974 createFBO(1, 1, 2, 4, 1);
1975 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03001976
1977 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1978 ASSERT_GL_NO_ERROR();
1979
1980 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +03001981 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1982 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03001983 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
1984}
1985
Martin Radevc1d4e552017-08-21 12:01:10 +03001986// The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
1987// potential bugs if the view is selected in the VS. The test contains a program in which the
1988// gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
1989// fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
1990// never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
1991// green for view 1.
1992TEST_P(MultiviewRenderTest, FlatInterpolation)
Martin Radev3c25ad02017-08-22 17:36:53 +03001993{
Martin Radevc1d4e552017-08-21 12:01:10 +03001994 if (!requestMultiviewExtension())
1995 {
1996 return;
1997 }
1998
Yuly Novikov1de29ab2017-09-07 18:07:23 -04001999 // TODO(mradev): Find out why this fails on Win10 Intel HD 630 D3D11
2000 // (http://anglebug.com/2062)
2001 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsD3D11());
2002
Martin Radevc1d4e552017-08-21 12:01:10 +03002003 const std::string vsSource =
2004 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002005 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002006 "layout(num_views = 2) in;\n"
2007 "in vec3 vPosition;\n"
2008 "flat out int oInstanceID;\n"
2009 "void main()\n"
2010 "{\n"
2011 " gl_Position = vec4(vPosition, 1.);\n"
2012 " oInstanceID = gl_InstanceID;\n"
2013 "}\n";
2014
2015 const std::string fsSource =
2016 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002017 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002018 "precision mediump float;\n"
2019 "flat in int oInstanceID;\n"
2020 "out vec4 col;\n"
2021 "void main()\n"
2022 "{\n"
2023 " if (oInstanceID < 0) {\n"
2024 " discard;\n"
2025 " }\n"
2026 " if (gl_ViewID_OVR == 0u) {\n"
2027 " col = vec4(1,0,0,1);\n"
2028 " } else {\n"
2029 " col = vec4(0,1,0,1);\n"
2030 " }\n"
2031 "}\n";
2032
2033 createFBO(1, 1, 2);
2034 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2035
2036 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2037 ASSERT_GL_NO_ERROR();
2038
2039 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2040 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +03002041}
2042
Martin Radev265a6d42017-09-12 16:51:37 +03002043// The test is added to cover a bug which resulted in the viewport/scissor and viewport offsets not
2044// being correctly applied.
2045TEST_P(MultiviewSideBySideRenderTest, ViewportOffsetsAppliedBugCoverage)
2046{
2047 if (!requestMultiviewExtension())
2048 {
2049 return;
2050 }
2051
2052 createFBO(1, 1, 2);
2053
2054 // Create multiview program.
2055 const std::string &vs =
2056 "#version 300 es\n"
2057 "#extension GL_OVR_multiview : require\n"
2058 "layout(num_views = 2) in;\n"
2059 "layout(location = 0) in vec3 vPosition;\n"
2060 "void main()\n"
2061 "{\n"
2062 " gl_Position = vec4(vPosition, 1.0);\n"
2063 "}\n";
2064
2065 const std::string &fs =
2066 "#version 300 es\n"
2067 "#extension GL_OVR_multiview : require\n"
2068 "precision mediump float;\n"
2069 "out vec4 col;\n"
2070 "void main()\n"
2071 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002072 " col = vec4(0,1,0,1);\n"
Martin Radev265a6d42017-09-12 16:51:37 +03002073 "}\n";
2074
2075 ANGLE_GL_PROGRAM(program, vs, fs);
2076
2077 glViewport(0, 0, 1, 1);
2078 glScissor(0, 0, 1, 1);
2079 glEnable(GL_SCISSOR_TEST);
2080 glClearColor(0, 0, 0, 1);
2081
2082 // Bind the default FBO and make sure that the state is synchronized.
2083 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
2084 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2085 ASSERT_GL_NO_ERROR();
2086
2087 // Draw and check that both views are rendered to.
2088 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
2089 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev67a8a012017-09-08 13:03:52 +03002090
Martin Radev265a6d42017-09-12 16:51:37 +03002091 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
Martin Radev67a8a012017-09-08 13:03:52 +03002092 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
2093 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev265a6d42017-09-12 16:51:37 +03002094}
2095
Martin Radevc1d4e552017-08-21 12:01:10 +03002096MultiviewImplementationParams VertexShaderOpenGL()
Martin Radev3c25ad02017-08-22 17:36:53 +03002097{
Martin Radevc1d4e552017-08-21 12:01:10 +03002098 return MultiviewImplementationParams(false, egl_platform::OPENGL());
Martin Radev3c25ad02017-08-22 17:36:53 +03002099}
2100
Martin Radevc1d4e552017-08-21 12:01:10 +03002101MultiviewImplementationParams VertexShaderD3D11()
Martin Radev3c25ad02017-08-22 17:36:53 +03002102{
Martin Radevc1d4e552017-08-21 12:01:10 +03002103 return MultiviewImplementationParams(false, egl_platform::D3D11());
Martin Radev3c25ad02017-08-22 17:36:53 +03002104}
2105
Martin Radevc1d4e552017-08-21 12:01:10 +03002106MultiviewImplementationParams GeomShaderD3D11()
Martin Radev72b4e1e2017-08-31 15:42:56 +03002107{
Martin Radevc1d4e552017-08-21 12:01:10 +03002108 return MultiviewImplementationParams(true, egl_platform::D3D11());
2109}
2110
2111MultiviewTestParams SideBySideVertexShaderOpenGL()
2112{
2113 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, VertexShaderOpenGL());
2114}
2115
2116MultiviewTestParams LayeredVertexShaderOpenGL()
2117{
2118 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, VertexShaderOpenGL());
2119}
2120
2121MultiviewTestParams SideBySideGeomShaderD3D11()
2122{
2123 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, GeomShaderD3D11());
2124}
2125
2126MultiviewTestParams LayeredGeomShaderD3D11()
2127{
2128 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, GeomShaderD3D11());
2129}
2130
2131MultiviewTestParams SideBySideVertexShaderD3D11()
2132{
2133 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, VertexShaderD3D11());
2134}
2135
2136MultiviewTestParams LayeredVertexShaderD3D11()
2137{
2138 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, VertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002139}
2140
Martin Radev8f276e22017-05-30 12:05:52 +03002141ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest, ES31_OPENGL());
Martin Radevced5c862017-08-17 16:05:29 +03002142ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002143 SideBySideVertexShaderOpenGL(),
2144 LayeredVertexShaderOpenGL(),
2145 SideBySideGeomShaderD3D11(),
2146 SideBySideVertexShaderD3D11(),
2147 LayeredGeomShaderD3D11(),
2148 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002149ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002150 SideBySideVertexShaderOpenGL(),
2151 LayeredVertexShaderOpenGL(),
2152 SideBySideGeomShaderD3D11(),
2153 SideBySideVertexShaderD3D11(),
2154 LayeredGeomShaderD3D11(),
2155 LayeredVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002156ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002157 SideBySideVertexShaderOpenGL(),
2158 LayeredVertexShaderOpenGL(),
2159 SideBySideGeomShaderD3D11(),
2160 SideBySideVertexShaderD3D11(),
2161 LayeredGeomShaderD3D11(),
2162 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002163ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002164 SideBySideVertexShaderOpenGL(),
2165 LayeredVertexShaderOpenGL(),
2166 SideBySideGeomShaderD3D11(),
2167 SideBySideVertexShaderD3D11(),
2168 LayeredGeomShaderD3D11(),
2169 LayeredVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002170ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002171 SideBySideVertexShaderOpenGL(),
2172 LayeredVertexShaderOpenGL(),
2173 SideBySideGeomShaderD3D11(),
2174 SideBySideVertexShaderD3D11(),
2175 LayeredGeomShaderD3D11(),
2176 LayeredVertexShaderD3D11());
2177ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest, VertexShaderOpenGL(), GeomShaderD3D11());
2178ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, VertexShaderOpenGL(), GeomShaderD3D11());