blob: e55f9d1e429db8674fac022b10f6f2370bb51116 [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
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400441 bool requestOcclusionQueryExtension()
442 {
443 if (extensionRequestable("GL_EXT_occlusion_query_boolean"))
444 {
445 glRequestExtensionANGLE("GL_EXT_occlusion_query_boolean");
446 }
447
448 if (!extensionEnabled("GL_EXT_occlusion_query_boolean"))
449 {
450 std::cout << "Test skipped due to missing GL_EXT_occlusion_query_boolean." << std::endl;
451 return false;
452 }
453 return true;
454 }
455
Martin Radev0d671c92017-08-10 16:41:52 +0300456 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
457 {
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400458 GLQueryEXT query;
459 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED, query);
Martin Radev0d671c92017-08-10 16:41:52 +0300460 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
461 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
462
463 GLuint result = GL_TRUE;
Geoff Lang8c5b31c2017-09-26 18:07:44 -0400464 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT, &result);
Martin Radev0d671c92017-08-10 16:41:52 +0300465 return result;
466 }
467};
468
Martin Radev3c25ad02017-08-22 17:36:53 +0300469class MultiviewProgramGenerationTest : public MultiviewRenderTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300470{
471 protected:
472 MultiviewProgramGenerationTest() {}
473};
474
Martin Radev3c25ad02017-08-22 17:36:53 +0300475class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300476{
477 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300478 MultiviewRenderPrimitiveTest() {}
Martin Radev61bd9992017-08-11 13:10:55 +0300479
480 void setupGeometry(const std::vector<Vector2> &vertexData)
481 {
Martin Radev61bd9992017-08-11 13:10:55 +0300482 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
483 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
484 GL_STATIC_DRAW);
485 glEnableVertexAttribArray(0);
486 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
487 }
488
Martin Radev67a8a012017-09-08 13:03:52 +0300489 void checkGreenChannel(const GLubyte expectedGreenChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300490 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300491 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300492 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300493 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300494 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300495 for (int h = 0; h < mViewHeight; ++h)
496 {
497 size_t flatIndex =
498 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
Martin Radev67a8a012017-09-08 13:03:52 +0300499 EXPECT_EQ(GLColor(0, expectedGreenChannelData[flatIndex], 0, 255),
Martin Radev3c25ad02017-08-22 17:36:53 +0300500 GetViewColor(w, h, view));
501 }
Martin Radev61bd9992017-08-11 13:10:55 +0300502 }
503 }
504 }
Martin Radev61bd9992017-08-11 13:10:55 +0300505 GLBuffer mVBO;
506};
507
Martin Radev3c25ad02017-08-22 17:36:53 +0300508class MultiviewSideBySideRenderTest : public MultiviewRenderTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300509 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev3c25ad02017-08-22 17:36:53 +0300510{
511 protected:
512 MultiviewSideBySideRenderTest()
513 : MultiviewRenderTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
514 {
515 }
516 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
Martin Radevc1d4e552017-08-21 12:01:10 +0300517 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
518 {
519 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
520 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300521};
522
Martin Radev72b4e1e2017-08-31 15:42:56 +0300523class MultiviewLayeredRenderTest : public MultiviewRenderTestBase,
Martin Radevc1d4e552017-08-21 12:01:10 +0300524 public ::testing::TestWithParam<MultiviewImplementationParams>
Martin Radev72b4e1e2017-08-31 15:42:56 +0300525{
526 protected:
527 MultiviewLayeredRenderTest()
528 : MultiviewRenderTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE)
529 {
530 }
531 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
Martin Radevc1d4e552017-08-21 12:01:10 +0300532 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
533 {
534 workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D;
535 }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300536};
537
Martin Radev14a26ae2017-07-24 15:56:29 +0300538// The test verifies that glDraw*Indirect:
539// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
540// than 1.
541// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +0300542TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300543{
544 if (!requestMultiviewExtension())
545 {
546 return;
547 }
548
Martin Radev14a26ae2017-07-24 15:56:29 +0300549 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +0300550
551 const std::string fsSource =
552 "#version 300 es\n"
553 "#extension GL_OVR_multiview : require\n"
554 "precision mediump float;\n"
555 "void main()\n"
556 "{}\n";
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
Martin Radev14a26ae2017-07-24 15:56:29 +0300564 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
565 {
566 const std::string &vsSource =
567 "#version 300 es\n"
568 "#extension GL_OVR_multiview : require\n"
569 "layout(num_views = 2) in;\n"
570 "void main()\n"
571 "{}\n";
572 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
573 glUseProgram(program);
574
Martin Radev7cf61662017-07-26 17:10:53 +0300575 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
576 0, 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300577
578 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
579 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
580
581 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
582 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
583 }
584
585 // Check that no errors are generated if the number of views is 1.
586 {
587 const std::string &vsSource =
588 "#version 300 es\n"
589 "#extension GL_OVR_multiview : require\n"
590 "layout(num_views = 1) in;\n"
591 "void main()\n"
592 "{}\n";
593 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
594 glUseProgram(program);
595
Martin Radev7cf61662017-07-26 17:10:53 +0300596 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
597 0, 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300598
599 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
600 EXPECT_GL_NO_ERROR();
601
602 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
603 EXPECT_GL_NO_ERROR();
604 }
605}
606
Martin Radev7cf61662017-07-26 17:10:53 +0300607// The test verifies that glDraw*:
608// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
609// program differs.
610// 2) does not generate any error if the number of views is the same.
Martin Radev7cf61662017-07-26 17:10:53 +0300611TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
612{
613 if (!requestMultiviewExtension())
614 {
615 return;
616 }
617
618 const GLint viewportOffsets[4] = {0, 0, 2, 0};
619
620 const std::string &vsSource =
621 "#version 300 es\n"
622 "#extension GL_OVR_multiview : require\n"
623 "layout(num_views = 2) in;\n"
624 "void main()\n"
625 "{}\n";
626 const std::string &fsSource =
627 "#version 300 es\n"
628 "#extension GL_OVR_multiview : require\n"
629 "precision mediump float;\n"
630 "void main()\n"
631 "{}\n";
632 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
633 glUseProgram(program);
634
635 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
636 // number of views.
637 {
638 // The framebuffer has only 1 view.
639 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
640 0, 1, &viewportOffsets[0]);
641
642 glDrawArrays(GL_TRIANGLES, 0, 3);
643 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
644
645 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
646 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
647 }
648
649 // Check that no errors are generated if the number of views in both program and draw
650 // framebuffer matches.
651 {
652 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
653 0, 2, &viewportOffsets[0]);
654
655 glDrawArrays(GL_TRIANGLES, 0, 3);
656 EXPECT_GL_NO_ERROR();
657
658 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
659 EXPECT_GL_NO_ERROR();
660 }
Martin Radevda8e2572017-09-12 17:21:16 +0300661}
Martin Radev7cf61662017-07-26 17:10:53 +0300662
Martin Radevda8e2572017-09-12 17:21:16 +0300663// The test verifies that glDraw* generates an INVALID_OPERATION error if the program does not use
664// the multiview extension, but the active draw framebuffer has more than one view.
665TEST_P(MultiviewDrawValidationTest, NumViewsMismatchForNonMultiviewProgram)
666{
667 if (!requestMultiviewExtension())
Martin Radev7cf61662017-07-26 17:10:53 +0300668 {
Martin Radevda8e2572017-09-12 17:21:16 +0300669 return;
Martin Radev7cf61662017-07-26 17:10:53 +0300670 }
Martin Radevda8e2572017-09-12 17:21:16 +0300671
672 const std::string &vsSourceNoMultiview =
673 "#version 300 es\n"
674 "void main()\n"
675 "{}\n";
676 const std::string &fsSourceNoMultiview =
677 "#version 300 es\n"
678 "precision mediump float;\n"
679 "void main()\n"
680 "{}\n";
681 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
682 glUseProgram(programNoMultiview);
683
684 const GLint viewportOffsets[4] = {0, 0, 2, 0};
685 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d, 0, 2,
686 &viewportOffsets[0]);
687
688 glDrawArrays(GL_TRIANGLES, 0, 3);
689 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
690
691 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
692 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
Martin Radev7cf61662017-07-26 17:10:53 +0300693}
694
Martin Radev7e69f762017-07-27 14:54:13 +0300695// The test verifies that glDraw*:
696// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
697// greater than 1 and there is an active transform feedback object.
698// 2) does not generate any error if the number of views in the draw framebuffer is 1.
699TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
700{
701 if (!requestMultiviewExtension())
702 {
703 return;
704 }
705
706 const GLint viewportOffsets[4] = {0, 0, 2, 0};
707
708 const std::string &vsSource =
709 "#version 300 es\n"
710 "void main()\n"
711 "{}\n";
712 const std::string &fsSource =
713 "#version 300 es\n"
714 "precision mediump float;\n"
715 "void main()\n"
716 "{}\n";
717 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
718 glUseProgram(program);
719
720 GLBuffer tbo;
721 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
722 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4u, nullptr, GL_STATIC_DRAW);
723
724 GLTransformFeedback transformFeedback;
725 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
726 glBeginTransformFeedback(GL_TRIANGLES);
727 ASSERT_GL_NO_ERROR();
728
729 // Check that drawArrays generates an error when there is an active transform feedback object
730 // and the number of views in the draw framebuffer is greater than 1.
731 {
732 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
733 0, 2, &viewportOffsets[0]);
734 glDrawArrays(GL_TRIANGLES, 0, 3);
735 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
736 }
737
738 // Check that drawArrays does not generate an error when the number of views in the draw
739 // framebuffer is 1.
740 {
741 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
742 0, 1, &viewportOffsets[0]);
743 glDrawArrays(GL_TRIANGLES, 0, 3);
744 EXPECT_GL_NO_ERROR();
745 }
746
747 glEndTransformFeedback();
748}
749
Martin Radevffe754b2017-07-31 10:38:07 +0300750// The test verifies that glDraw*:
751// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
752// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
753// 2) does not generate any error if the number of views in the draw framebuffer is 1.
754TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
755{
756 if (!requestMultiviewExtension())
757 {
758 return;
759 }
760
761 if (!extensionEnabled("GL_EXT_disjoint_timer_query"))
762 {
763 std::cout << "Test skipped because GL_EXT_disjoint_timer_query is not available."
764 << std::endl;
765 return;
766 }
767
768 const GLint viewportOffsets[4] = {0, 0, 2, 0};
769 const std::string &vsSource =
770 "#version 300 es\n"
771 "void main()\n"
772 "{}\n";
773 const std::string &fsSource =
774 "#version 300 es\n"
775 "precision mediump float;\n"
776 "void main()\n"
777 "{}\n";
778 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
779 glUseProgram(program);
780
781 GLuint query = 0u;
782 glGenQueriesEXT(1, &query);
783 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
784
785 // Check first case.
786 {
787 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
788 0, 2, &viewportOffsets[0]);
789 glDrawArrays(GL_TRIANGLES, 0, 3);
790 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
791 }
792
793 // Check second case.
794 {
795 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
796 0, 1, &viewportOffsets[0]);
797 glDrawArrays(GL_TRIANGLES, 0, 3);
798 EXPECT_GL_NO_ERROR();
799 }
800
801 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
802 glDeleteQueries(1, &query);
803}
804
Martin Radev8f276e22017-05-30 12:05:52 +0300805// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300806TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300807{
808 if (!requestMultiviewExtension())
809 {
810 return;
811 }
812 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
813 ASSERT_GL_NO_ERROR();
814
815 checkOutput();
816}
817
818// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300819TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300820{
821 if (!requestMultiviewExtension())
822 {
823 return;
824 }
825 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
826 ASSERT_GL_NO_ERROR();
827
828 checkOutput();
829}
830
831// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300832TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300833{
834 if (!requestMultiviewExtension())
835 {
836 return;
837 }
838 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
839 ASSERT_GL_NO_ERROR();
840
841 checkOutput();
842}
843
844// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300845TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300846{
847 if (!requestMultiviewExtension())
848 {
849 return;
850 }
851
852 const std::string vsSource =
853 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300854 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300855 "layout(num_views = 4) in;\n"
856 "in vec4 vPosition;\n"
857 "void main()\n"
858 "{\n"
859 " if (gl_ViewID_OVR == 0u) {\n"
860 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
861 " } else if (gl_ViewID_OVR == 1u) {\n"
862 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
863 " } else if (gl_ViewID_OVR == 2u) {\n"
864 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
865 " } else {\n"
866 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
867 " }"
868 " gl_Position.yzw = vPosition.yzw;\n"
869 "}\n";
870
871 const std::string fsSource =
872 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300873 "#extension GL_OVR_multiview : require\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300874 "precision mediump float;\n"
875 "out vec4 col;\n"
876 "void main()\n"
877 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300878 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300879 "}\n";
880
Martin Radev3c25ad02017-08-22 17:36:53 +0300881 createFBO(4, 1, 4);
Martin Radev8f276e22017-05-30 12:05:52 +0300882 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +0300883
884 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
885 ASSERT_GL_NO_ERROR();
886
887 for (int i = 0; i < 4; ++i)
888 {
889 for (int j = 0; j < 4; ++j)
890 {
Martin Radev8f276e22017-05-30 12:05:52 +0300891 if (i == j)
892 {
Martin Radev67a8a012017-09-08 13:03:52 +0300893 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300894 }
895 else
896 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300897 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300898 }
899 }
900 }
901 EXPECT_GL_NO_ERROR();
902}
903
904// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300905TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +0300906{
907 if (!requestMultiviewExtension())
908 {
909 return;
910 }
911
912 const std::string vsSource =
913 "#version 300 es\n"
914 "#extension GL_OVR_multiview : require\n"
915 "layout(num_views = 2) in;\n"
916 "in vec4 vPosition;\n"
917 "void main()\n"
918 "{\n"
919 " vec4 p = vPosition;\n"
920 " if (gl_InstanceID == 1){\n"
921 " p.y = .5*p.y + .5;\n"
922 " } else {\n"
923 " p.y = p.y*.5;\n"
924 " }\n"
925 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x*0.5 + 0.5 : p.x*0.5);\n"
926 " gl_Position.yzw = p.yzw;\n"
927 "}\n";
928
929 const std::string fsSource =
930 "#version 300 es\n"
931 "#extension GL_OVR_multiview : require\n"
932 "precision mediump float;\n"
933 "out vec4 col;\n"
934 "void main()\n"
935 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +0300936 " col = vec4(0,1,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300937 "}\n";
938
Martin Radev3c25ad02017-08-22 17:36:53 +0300939 const int kViewWidth = 2;
940 const int kViewHeight = 2;
941 const int kNumViews = 2;
942 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev8f276e22017-05-30 12:05:52 +0300943 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev8f276e22017-05-30 12:05:52 +0300944
Martin Radev67a8a012017-09-08 13:03:52 +0300945 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 2u);
Martin Radev8f276e22017-05-30 12:05:52 +0300946 ASSERT_GL_NO_ERROR();
947
Martin Radev67a8a012017-09-08 13:03:52 +0300948 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
949 {{255, 0}, {255, 0}}};
Martin Radev3c25ad02017-08-22 17:36:53 +0300950
951 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +0300952 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300953 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +0300954 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300955 for (int x = 0; x < 2; ++x)
956 {
Martin Radev67a8a012017-09-08 13:03:52 +0300957 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][y][x], 0, 255),
Martin Radev3c25ad02017-08-22 17:36:53 +0300958 GetViewColor(x, y, view));
959 }
Martin Radev8f276e22017-05-30 12:05:52 +0300960 }
961 }
962}
963
Martin Radev553590a2017-07-31 16:40:39 +0300964// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
965// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
966// offset of each quad are passed as separate attributes which are indexed based on the
967// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
968// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
969// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
970// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +0300971TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +0300972{
973 if (!requestMultiviewExtension())
974 {
975 return;
976 }
977
978 const std::string &vsSource =
979 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300980 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +0300981 "layout(num_views = 2) in;\n"
982 "in vec3 vPosition;\n"
983 "in float offsetX;\n"
984 "in float offsetY;\n"
985 "void main()\n"
986 "{\n"
987 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +0300988 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300989 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
990 " gl_Position.yzw = p.yzw;\n"
991 "}\n";
992
993 const std::string &fsSource =
994 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +0300995 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +0300996 "precision mediump float;\n"
997 "out vec4 col;\n"
998 "void main()\n"
999 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001000 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001001 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +03001002
1003 const int kViewWidth = 4;
1004 const int kViewHeight = 4;
1005 const int kNumViews = 2;
1006 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev553590a2017-07-31 16:40:39 +03001007 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev553590a2017-07-31 16:40:39 +03001008
1009 GLBuffer xOffsetVBO;
1010 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1011 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
1012 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
1013 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1014 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1015 glVertexAttribDivisor(xOffsetLoc, 3);
1016 glEnableVertexAttribArray(xOffsetLoc);
1017
1018 GLBuffer yOffsetVBO;
1019 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1020 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1021 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1022 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1023 glVertexAttribDivisor(yOffsetLoc, 1);
1024 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1025 glEnableVertexAttribArray(yOffsetLoc);
1026
Martin Radev67a8a012017-09-08 13:03:52 +03001027 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev553590a2017-07-31 16:40:39 +03001028 ASSERT_GL_NO_ERROR();
1029
Martin Radev67a8a012017-09-08 13:03:52 +03001030 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001031 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1032 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1033 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +03001034 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001035 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +03001036 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001037 for (int col = 0; col < 4; ++col)
1038 {
Martin Radev67a8a012017-09-08 13:03:52 +03001039 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0, 255),
Martin Radev3c25ad02017-08-22 17:36:53 +03001040 GetViewColor(col, row, view));
1041 }
Martin Radev553590a2017-07-31 16:40:39 +03001042 }
1043 }
1044}
1045
1046// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1047// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +03001048TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +03001049{
1050 if (!requestMultiviewExtension())
1051 {
1052 return;
1053 }
1054
Martin Radev3c25ad02017-08-22 17:36:53 +03001055 createFBO(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +03001056
1057 // Create multiview program.
1058 const std::string &vs =
1059 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001060 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001061 "layout(num_views = 2) in;\n"
1062 "layout(location = 0) in vec2 vPosition;\n"
1063 "layout(location = 1) in float offsetX;\n"
1064 "void main()\n"
1065 "{\n"
1066 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1067 " p.x += offsetX;\n"
1068 " gl_Position = p;\n"
1069 "}\n";
1070
1071 const std::string &fs =
1072 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001073 "#extension GL_OVR_multiview : require\n"
Martin Radev553590a2017-07-31 16:40:39 +03001074 "precision mediump float;\n"
1075 "out vec4 col;\n"
1076 "void main()\n"
1077 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001078 " col = vec4(0,1,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001079 "}\n";
1080
1081 ANGLE_GL_PROGRAM(program, vs, fs);
1082
1083 const std::string &dummyVS =
1084 "#version 300 es\n"
1085 "layout(location = 0) in vec2 vPosition;\n"
1086 "layout(location = 1) in float offsetX;\n"
1087 "void main()\n"
1088 "{\n"
1089 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1090 "}\n";
1091
1092 const std::string &dummyFS =
1093 "#version 300 es\n"
1094 "precision mediump float;\n"
1095 "out vec4 col;\n"
1096 "void main()\n"
1097 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001098 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001099 "}\n";
1100
1101 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
1102
1103 GLBuffer xOffsetVBO;
1104 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1105 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1106 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1107 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1108
1109 GLBuffer vertexVBO;
1110 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1111 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1112 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1113 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1114
1115 GLVertexArray vao[2];
1116 for (size_t i = 0u; i < 2u; ++i)
1117 {
1118 glBindVertexArray(vao[i]);
1119
1120 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1121 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1122 glEnableVertexAttribArray(0);
1123
1124 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1125 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1126 glEnableVertexAttribArray(1);
1127 }
1128 ASSERT_GL_NO_ERROR();
1129
1130 glViewport(0, 0, 1, 1);
1131 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001132 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001133 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001134
1135 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1136 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1137 // bits are cleared.
1138 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001139 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1140 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001141 glBindVertexArray(vao[0]);
1142 glVertexAttribDivisor(1, 0);
1143 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1144 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001145 ASSERT_GL_NO_ERROR();
1146
1147 // Check that vertexAttribDivisor uses the number of views to update the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001148 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
1149 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001150 glUseProgram(program);
1151 glVertexAttribDivisor(1, 1);
1152 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001153 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1154 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001155
1156 // Clear the buffers and propagate divisor to the driver.
1157 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1158 // dirty bits when useProgram is called.
1159 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001160 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1161 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001162 glVertexAttribDivisor(1, 1);
1163 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1164 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001165 ASSERT_GL_NO_ERROR();
1166
1167 // Check that useProgram uses the number of views to update the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001168 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
1169 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001170 glUseProgram(program);
1171 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001172 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1173 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001174
1175 // We go through similar steps as before.
1176 glUseProgram(dummyProgram);
Martin Radevda8e2572017-09-12 17:21:16 +03001177 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1178 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001179 glVertexAttribDivisor(1, 1);
1180 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1181 glUseProgram(0);
Martin Radev553590a2017-07-31 16:40:39 +03001182 ASSERT_GL_NO_ERROR();
1183
1184 // Check that bindVertexArray uses the number of views to update the divisor.
1185 {
1186 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1187 // divisor for vao[1] only.
Martin Radevda8e2572017-09-12 17:21:16 +03001188 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
1189 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001190 glBindVertexArray(vao[1]);
1191 glUseProgram(program);
1192 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001193 glBindVertexArray(0);
1194 ASSERT_GL_NO_ERROR();
1195 }
1196 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1197 // adjusts the divisor.
Martin Radevda8e2572017-09-12 17:21:16 +03001198 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev553590a2017-07-31 16:40:39 +03001199 glBindVertexArray(vao[0]);
1200 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev67a8a012017-09-08 13:03:52 +03001201 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1202 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001203}
1204
Martin Radev0d671c92017-08-10 16:41:52 +03001205// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1206// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001207TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001208{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001209 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1210 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001211
1212 const std::string vsSource =
1213 "#version 300 es\n"
1214 "#extension GL_OVR_multiview : require\n"
1215 "layout(num_views = 2) in;\n"
1216 "in vec3 vPosition;\n"
1217 "void main()\n"
1218 "{\n"
1219 " gl_Position.x = 2.0;\n"
1220 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1221 "}\n";
1222
1223 const std::string fsSource =
1224 "#version 300 es\n"
1225 "#extension GL_OVR_multiview : require\n"
1226 "precision mediump float;\n"
1227 "out vec4 col;\n"
1228 "void main()\n"
1229 "{\n"
1230 " col = vec4(1,0,0,0);\n"
1231 "}\n";
1232 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev3c25ad02017-08-22 17:36:53 +03001233 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001234
1235 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1236 ASSERT_GL_NO_ERROR();
1237 EXPECT_GL_FALSE(result);
1238}
1239
1240// Test that there are fragments passing the occlusion query if only view 0 can produce
1241// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001242TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001243{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001244 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1245 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001246
1247 const std::string vsSource =
1248 "#version 300 es\n"
1249 "#extension GL_OVR_multiview : require\n"
1250 "layout(num_views = 2) in;\n"
1251 "in vec3 vPosition;\n"
1252 "void main()\n"
1253 "{\n"
1254 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1255 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1256 "}\n";
1257
1258 const std::string fsSource =
1259 "#version 300 es\n"
1260 "#extension GL_OVR_multiview : require\n"
1261 "precision mediump float;\n"
1262 "out vec4 col;\n"
1263 "void main()\n"
1264 "{\n"
1265 " col = vec4(1,0,0,0);\n"
1266 "}\n";
1267 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev3c25ad02017-08-22 17:36:53 +03001268 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001269
1270 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1271 ASSERT_GL_NO_ERROR();
1272 EXPECT_GL_TRUE(result);
1273}
1274
1275// Test that there are fragments passing the occlusion query if only view 1 can produce
1276// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001277TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001278{
Geoff Lang8c5b31c2017-09-26 18:07:44 -04001279 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1280 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
Martin Radev0d671c92017-08-10 16:41:52 +03001281
1282 const std::string vsSource =
1283 "#version 300 es\n"
1284 "#extension GL_OVR_multiview : require\n"
1285 "layout(num_views = 2) in;\n"
1286 "in vec3 vPosition;\n"
1287 "void main()\n"
1288 "{\n"
1289 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1290 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1291 "}\n";
1292
1293 const std::string fsSource =
1294 "#version 300 es\n"
1295 "#extension GL_OVR_multiview : require\n"
1296 "precision mediump float;\n"
1297 "out vec4 col;\n"
1298 "void main()\n"
1299 "{\n"
1300 " col = vec4(1,0,0,0);\n"
1301 "}\n";
1302 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev3c25ad02017-08-22 17:36:53 +03001303 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001304
1305 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1306 ASSERT_GL_NO_ERROR();
1307 EXPECT_GL_TRUE(result);
1308}
1309
Martin Radev41ac68e2017-06-06 12:16:58 +03001310// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1311// compiles and links without an error.
1312TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1313{
1314 if (!requestMultiviewExtension())
1315 {
1316 return;
1317 }
1318
1319 const std::string vsSource =
1320 "#version 300 es\n"
1321 "#extension GL_OVR_multiview : require\n"
1322 "layout(num_views = 2) in;\n"
1323 "void main()\n"
1324 "{\n"
1325 "}\n";
1326
1327 const std::string fsSource =
1328 "#version 300 es\n"
1329 "#extension GL_OVR_multiview : require\n"
1330 "precision mediump float;\n"
1331 "void main()\n"
1332 "{\n"
1333 "}\n";
1334
1335 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1336 glUseProgram(program);
1337
1338 EXPECT_GL_NO_ERROR();
1339}
1340
1341// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1342// without an error.
1343TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1344{
1345 if (!requestMultiviewExtension())
1346 {
1347 return;
1348 }
1349
1350 const std::string vsSource =
1351 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001352 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001353 "layout(num_views = 2) in;\n"
1354 "void main()\n"
1355 "{\n"
1356 " if (gl_ViewID_OVR == 0u) {\n"
1357 " gl_Position = vec4(1,0,0,1);\n"
1358 " } else {\n"
1359 " gl_Position = vec4(-1,0,0,1);\n"
1360 " }\n"
1361 "}\n";
1362
1363 const std::string fsSource =
1364 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001365 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001366 "precision mediump float;\n"
1367 "void main()\n"
1368 "{\n"
1369 "}\n";
1370
1371 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1372 glUseProgram(program);
1373
1374 EXPECT_GL_NO_ERROR();
1375}
1376
1377// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1378// without an error.
1379TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1380{
1381 if (!requestMultiviewExtension())
1382 {
1383 return;
1384 }
1385
1386 const std::string vsSource =
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 "layout(num_views = 2) in;\n"
1390 "void main()\n"
1391 "{\n"
1392 "}\n";
1393
1394 const std::string fsSource =
1395 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001396 "#extension GL_OVR_multiview : require\n"
Martin Radev41ac68e2017-06-06 12:16:58 +03001397 "precision mediump float;\n"
1398 "out vec4 col;\n"
1399 "void main()\n"
1400 "{\n"
1401 " if (gl_ViewID_OVR == 0u) {\n"
1402 " col = vec4(1,0,0,1);\n"
1403 " } else {\n"
1404 " col = vec4(-1,0,0,1);\n"
1405 " }\n"
1406 "}\n";
1407
1408 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1409 glUseProgram(program);
1410
1411 EXPECT_GL_NO_ERROR();
1412}
1413
Martin Radev61bd9992017-08-11 13:10:55 +03001414// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001415TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001416{
1417 if (!requestMultiviewExtension())
1418 {
1419 return;
1420 }
1421
1422 const std::string vsSource =
1423 "#version 300 es\n"
1424 "#extension GL_OVR_multiview : require\n"
1425 "layout(num_views = 2) in;\n"
1426 "layout(location=0) in vec2 vPosition;\n"
1427 "void main()\n"
1428 "{\n"
1429 " gl_PointSize = 1.0;\n"
1430 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1431 "}\n";
1432
1433 const std::string fsSource =
1434 "#version 300 es\n"
1435 "#extension GL_OVR_multiview : require\n"
1436 "precision mediump float;\n"
1437 "out vec4 col;\n"
1438 "void main()\n"
1439 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001440 " col = vec4(0,1,0,1);\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001441 "}\n";
1442 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1443 glUseProgram(program);
1444
Martin Radev3c25ad02017-08-22 17:36:53 +03001445 const int kViewWidth = 4;
1446 const int kViewHeight = 2;
1447 const int kNumViews = 2;
1448 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001449
1450 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1451 std::vector<Vector2> vertexDataInClipSpace =
1452 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1453 setupGeometry(vertexDataInClipSpace);
1454
1455 glDrawArrays(GL_POINTS, 0, 2);
1456
Martin Radev67a8a012017-09-08 13:03:52 +03001457 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001458 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001459 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001460}
1461
1462// The test checks that GL_LINES is correctly rendered.
1463// The behavior of this test is not guaranteed by the spec:
1464// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1465// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1466// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1467// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001468TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001469{
1470 if (!requestMultiviewExtension())
1471 {
1472 return;
1473 }
1474
Martin Radevced5c862017-08-17 16:05:29 +03001475 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001476 ASSERT_NE(program, 0u);
1477 glUseProgram(program);
1478 ASSERT_GL_NO_ERROR();
1479
Martin Radev3c25ad02017-08-22 17:36:53 +03001480 const int kViewWidth = 4;
1481 const int kViewHeight = 2;
1482 const int kNumViews = 2;
1483 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001484
1485 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1486 std::vector<Vector2> vertexDataInClipSpace =
1487 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1488 setupGeometry(vertexDataInClipSpace);
1489
1490 glDrawArrays(GL_LINES, 0, 2);
1491
Martin Radev67a8a012017-09-08 13:03:52 +03001492 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001493 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001494 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001495
1496 glDeleteProgram(program);
1497}
1498
1499// The test checks that GL_LINE_STRIP is correctly rendered.
1500// The behavior of this test is not guaranteed by the spec:
1501// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1502// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1503// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1504// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001505TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001506{
1507 if (!requestMultiviewExtension())
1508 {
1509 return;
1510 }
1511
Martin Radevced5c862017-08-17 16:05:29 +03001512 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001513 ASSERT_NE(program, 0u);
1514 glUseProgram(program);
1515 ASSERT_GL_NO_ERROR();
1516
Martin Radev3c25ad02017-08-22 17:36:53 +03001517 const int kViewWidth = 4;
1518 const int kViewHeight = 2;
1519 const int kNumViews = 2;
1520 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001521
1522 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1523 std::vector<Vector2> vertexDataInClipSpace =
1524 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1525 setupGeometry(vertexDataInClipSpace);
1526
1527 glDrawArrays(GL_LINE_STRIP, 0, 3);
1528
Martin Radev67a8a012017-09-08 13:03:52 +03001529 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001530 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001531 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001532
1533 glDeleteProgram(program);
1534}
1535
1536// The test checks that GL_LINE_LOOP is correctly rendered.
1537// The behavior of this test is not guaranteed by the spec:
1538// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1539// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1540// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1541// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001542TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001543{
1544 if (!requestMultiviewExtension())
1545 {
1546 return;
1547 }
1548
Martin Radevced5c862017-08-17 16:05:29 +03001549 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001550 ASSERT_NE(program, 0u);
1551 glUseProgram(program);
1552 ASSERT_GL_NO_ERROR();
1553
Martin Radev3c25ad02017-08-22 17:36:53 +03001554 const int kViewWidth = 4;
1555 const int kViewHeight = 4;
1556 const int kNumViews = 2;
1557 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001558
1559 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1560 Vector2I(0, 3)};
1561 std::vector<Vector2> vertexDataInClipSpace =
1562 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1563 setupGeometry(vertexDataInClipSpace);
1564
1565 glDrawArrays(GL_LINE_LOOP, 0, 4);
1566
Martin Radev67a8a012017-09-08 13:03:52 +03001567 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
Martin Radev3c25ad02017-08-22 17:36:53 +03001568 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1569 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
Martin Radev67a8a012017-09-08 13:03:52 +03001570 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001571
1572 glDeleteProgram(program);
1573}
1574
1575// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001576TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001577{
1578 if (!requestMultiviewExtension())
1579 {
1580 return;
1581 }
1582
Martin Radevced5c862017-08-17 16:05:29 +03001583 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001584 ASSERT_NE(program, 0u);
1585 glUseProgram(program);
1586 ASSERT_GL_NO_ERROR();
1587
1588 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1589 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1590 setupGeometry(vertexDataInClipSpace);
1591
Martin Radev3c25ad02017-08-22 17:36:53 +03001592 const int kViewWidth = 2;
1593 const int kViewHeight = 2;
1594 const int kNumViews = 2;
1595 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001596
1597 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1598
Martin Radev67a8a012017-09-08 13:03:52 +03001599 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1600 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1601 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001602
1603 glDeleteProgram(program);
1604}
1605
1606// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001607TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001608{
1609 if (!requestMultiviewExtension())
1610 {
1611 return;
1612 }
1613
Martin Radevced5c862017-08-17 16:05:29 +03001614 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001615 ASSERT_NE(program, 0u);
1616 glUseProgram(program);
1617 ASSERT_GL_NO_ERROR();
1618
1619 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1620 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1621 setupGeometry(vertexDataInClipSpace);
1622
Martin Radev3c25ad02017-08-22 17:36:53 +03001623 const int kViewWidth = 2;
1624 const int kViewHeight = 2;
1625 const int kNumViews = 2;
1626 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001627
1628 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1629
Martin Radev67a8a012017-09-08 13:03:52 +03001630 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1631 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1632 checkGreenChannel(expectedGreenChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001633
1634 glDeleteProgram(program);
1635}
1636
1637// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1638// bounds. The test does not rely on the actual line width being greater than 1.0.
Martin Radev3c25ad02017-08-22 17:36:53 +03001639TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
Martin Radev61bd9992017-08-11 13:10:55 +03001640{
1641 if (!requestMultiviewExtension())
1642 {
1643 return;
1644 }
1645
Martin Radev3c25ad02017-08-22 17:36:53 +03001646 createFBO(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +03001647
1648 GLint viewportOffsets[4] = {1, 0, 3, 0};
1649 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1650 mColorTexture, 0, 2, &viewportOffsets[0]);
1651 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
1652 mDepthTexture, 0, 2, &viewportOffsets[0]);
1653
1654 glViewport(0, 0, 1, 1);
1655 glScissor(0, 0, 1, 1);
1656 glEnable(GL_SCISSOR_TEST);
1657
1658 const std::string vsSource =
1659 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001660 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001661 "layout(num_views = 2) in;\n"
1662 "layout(location=0) in vec2 vPosition;\n"
1663 "void main()\n"
1664 "{\n"
1665 " gl_PointSize = 10.0;\n"
1666 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1667 "}\n";
1668
1669 const std::string fsSource =
1670 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001671 "#extension GL_OVR_multiview : require\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001672 "precision mediump float;\n"
1673 "out vec4 col;\n"
1674 "void main()\n"
1675 "{\n"
1676 " if (gl_ViewID_OVR == 0u) {\n"
1677 " col = vec4(1,0,0,1);\n"
1678 " } else {\n"
1679 " col = vec4(0,1,0,1);\n"
1680 " }\n"
1681 "}\n";
1682 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1683 glUseProgram(program);
1684
1685 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1686 const std::vector<Vector2> &vertexDataInClipSpace =
1687 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001688
1689 GLBuffer vbo;
1690 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1691 glBufferData(GL_ARRAY_BUFFER, vertexDataInClipSpace.size() * sizeof(Vector2),
1692 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1693 glEnableVertexAttribArray(0);
1694 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
Martin Radev61bd9992017-08-11 13:10:55 +03001695
1696 // Test rendering points.
1697 {
1698 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1699 glDrawArrays(GL_POINTS, 0, 2);
1700 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1701 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1702 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1703 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1704 }
1705
1706 // Test rendering lines.
1707 {
1708 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1709 glLineWidth(10.f);
1710 glDrawArrays(GL_LINES, 0, 2);
1711 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1712 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1713 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1714 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1715 }
1716}
1717
Martin Radev0abb7a22017-08-28 15:34:45 +03001718// Verify that re-linking a program adjusts the attribute divisor.
1719// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1720// to each other. The quads' position and color depend on the corresponding attribute divisors.
1721TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1722{
1723 if (!requestMultiviewExtension())
1724 {
1725 return;
1726 }
1727
1728 const int kViewWidth = 4;
1729 const int kViewHeight = 1;
1730 const int kNumViews = 2;
1731
1732 const std::string &fsSource =
1733 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001734 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001735 "precision mediump float;\n"
1736 "in vec4 oColor;\n"
1737 "out vec4 col;\n"
1738 "void main()\n"
1739 "{\n"
1740 " col = oColor;\n"
1741 "}\n";
1742
1743 auto generateVertexShaderSource = [](int numViews) -> std::string {
1744 std::string source =
1745 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001746 "#extension GL_OVR_multiview : require\n"
Martin Radev0abb7a22017-08-28 15:34:45 +03001747 "layout(num_views = " +
1748 ToString(numViews) +
1749 ") in;\n"
1750 "in vec3 vPosition;\n"
1751 "in float vOffsetX;\n"
1752 "in vec4 vColor;\n"
1753 "out vec4 oColor;\n"
1754 "void main()\n"
1755 "{\n"
1756 " vec4 p = vec4(vPosition, 1.);\n"
1757 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1758 " oColor = vColor;\n"
1759 " gl_Position = p;\n"
1760 "}\n";
1761 return source;
1762 };
1763
1764 std::string vsSource = generateVertexShaderSource(kNumViews);
1765 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1766 glUseProgram(program);
1767
1768 GLint positionLoc;
1769 GLBuffer xOffsetVBO;
1770 GLint xOffsetLoc;
1771 GLBuffer colorVBO;
1772 GLint colorLoc;
1773
1774 {
1775 // Initialize buffers and setup attributes.
1776 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1777 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1778 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1779 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1780 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1781 glVertexAttribDivisor(xOffsetLoc, 1);
1782 glEnableVertexAttribArray(xOffsetLoc);
1783
1784 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1785 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1786 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1787 colorLoc = glGetAttribLocation(program, "vColor");
1788 glVertexAttribDivisor(colorLoc, 2);
1789 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1790 glEnableVertexAttribArray(colorLoc);
1791
1792 positionLoc = glGetAttribLocation(program, "vPosition");
1793 }
1794
1795 {
1796 createFBO(kViewWidth, kViewHeight, kNumViews);
1797
Martin Radev67a8a012017-09-08 13:03:52 +03001798 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001799 ASSERT_GL_NO_ERROR();
1800
1801 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1802 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1803 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1804 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1805 }
1806
1807 {
1808 const int kNewNumViews = 3;
1809 vsSource = generateVertexShaderSource(kNewNumViews);
1810 createFBO(kViewWidth, kViewHeight, kNewNumViews);
1811
1812 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
1813 ASSERT_NE(0u, vs);
1814 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
1815 ASSERT_NE(0u, fs);
1816
1817 GLint numAttachedShaders = 0;
1818 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1819
1820 GLuint attachedShaders[2] = {0u};
1821 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1822 for (int i = 0; i < 2; ++i)
1823 {
1824 glDetachShader(program, attachedShaders[i]);
1825 }
1826
1827 glAttachShader(program, vs);
1828 glDeleteShader(vs);
1829
1830 glAttachShader(program, fs);
1831 glDeleteShader(fs);
1832
1833 glBindAttribLocation(program, positionLoc, "vPosition");
1834 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1835 glBindAttribLocation(program, colorLoc, "vColor");
1836
1837 glLinkProgram(program);
1838
Martin Radev67a8a012017-09-08 13:03:52 +03001839 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
Martin Radev0abb7a22017-08-28 15:34:45 +03001840 ASSERT_GL_NO_ERROR();
1841
1842 for (int i = 0; i < kNewNumViews; ++i)
1843 {
1844 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1845 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1846 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1847 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1848 }
1849 }
1850}
1851
Martin Radevced5c862017-08-17 16:05:29 +03001852// Test that useProgram applies the number of views in computing the final value of the attribute
1853// divisor.
1854TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1855{
1856 if (!requestMultiviewExtension())
1857 {
1858 return;
1859 }
1860
1861 GLVertexArray vao;
1862 glBindVertexArray(vao);
1863 GLBuffer vbo;
1864 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1865 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
1866 Vector2I(3, 0)};
1867 std::vector<Vector2> vertexDataInClipSpace =
1868 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
1869 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
1870 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
1871 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1872 glEnableVertexAttribArray(0);
1873 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
1874 glVertexAttribDivisor(0, 1);
1875 ASSERT_GL_NO_ERROR();
1876
1877 // Create a program and fbo with N views and draw N instances of a point horizontally.
1878 for (int numViews = 2; numViews <= 4; ++numViews)
1879 {
1880 createFBO(4, 1, numViews);
1881 ASSERT_GL_NO_ERROR();
1882
1883 GLuint program = CreateSimplePassthroughProgram(numViews);
1884 ASSERT_NE(program, 0u);
1885 glUseProgram(program);
1886 ASSERT_GL_NO_ERROR();
1887
1888 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
1889
1890 for (int view = 0; view < numViews; ++view)
1891 {
1892 for (int j = 0; j < numViews; ++j)
1893 {
Martin Radev67a8a012017-09-08 13:03:52 +03001894 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
Martin Radevced5c862017-08-17 16:05:29 +03001895 }
1896 for (int j = numViews; j < 4; ++j)
1897 {
1898 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, view));
1899 }
1900 }
1901
1902 glDeleteProgram(program);
1903 }
1904}
1905
Martin Radev72b4e1e2017-08-31 15:42:56 +03001906// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
1907TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
1908{
1909 if (!requestMultiviewExtension())
1910 {
1911 return;
1912 }
1913
1914 const std::string vsSource =
1915 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001916 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001917 "layout(num_views = 3) in;\n"
1918 "in vec3 vPosition;\n"
1919 "void main()\n"
1920 "{\n"
1921 " gl_Position = vec4(vPosition, 1.);\n"
1922 "}\n";
1923
1924 const std::string fsSource =
1925 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03001926 "#extension GL_OVR_multiview : require\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001927 "precision mediump float;\n"
1928 "out vec4 col;\n"
1929 "void main()\n"
1930 "{\n"
1931 " if (gl_ViewID_OVR == 0u) {\n"
1932 " col = vec4(1,0,0,1);\n"
1933 " } else if (gl_ViewID_OVR == 1u) {\n"
1934 " col = vec4(0,1,0,1);\n"
1935 " } else if (gl_ViewID_OVR == 2u) {\n"
1936 " col = vec4(0,0,1,1);\n"
1937 " } else {\n"
1938 " col = vec4(0,0,0,0);\n"
1939 " }\n"
1940 "}\n";
1941
1942 createFBO(1, 1, 3);
1943 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03001944
1945 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1946 ASSERT_GL_NO_ERROR();
1947
1948 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1949 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1950 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
1951}
1952
1953// The test checks that the inactive layers of a 2D texture array are not written to by a
1954// multi-view program.
1955TEST_P(MultiviewLayeredRenderTest, RenderToSubrageOfLayers)
1956{
1957 if (!requestMultiviewExtension())
1958 {
1959 return;
1960 }
1961
1962 const std::string vsSource =
1963 "#version 300 es\n"
1964 "#extension GL_OVR_multiview : require\n"
1965 "layout(num_views = 2) in;\n"
1966 "in vec3 vPosition;\n"
1967 "void main()\n"
1968 "{\n"
1969 " gl_Position = vec4(vPosition, 1.);\n"
1970 "}\n";
1971
1972 const std::string fsSource =
1973 "#version 300 es\n"
1974 "#extension GL_OVR_multiview : require\n"
1975 "precision mediump float;\n"
1976 "out vec4 col;\n"
1977 "void main()\n"
1978 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03001979 " col = vec4(0,1,0,1);\n"
Martin Radev72b4e1e2017-08-31 15:42:56 +03001980 "}\n";
1981
1982 createFBO(1, 1, 2, 4, 1);
1983 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
Martin Radev72b4e1e2017-08-31 15:42:56 +03001984
1985 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1986 ASSERT_GL_NO_ERROR();
1987
1988 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
Martin Radev67a8a012017-09-08 13:03:52 +03001989 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1990 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
Martin Radev72b4e1e2017-08-31 15:42:56 +03001991 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
1992}
1993
Martin Radevc1d4e552017-08-21 12:01:10 +03001994// The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
1995// potential bugs if the view is selected in the VS. The test contains a program in which the
1996// gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
1997// fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
1998// never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
1999// green for view 1.
2000TEST_P(MultiviewRenderTest, FlatInterpolation)
Martin Radev3c25ad02017-08-22 17:36:53 +03002001{
Martin Radevc1d4e552017-08-21 12:01:10 +03002002 if (!requestMultiviewExtension())
2003 {
2004 return;
2005 }
2006
Yuly Novikov1de29ab2017-09-07 18:07:23 -04002007 // TODO(mradev): Find out why this fails on Win10 Intel HD 630 D3D11
2008 // (http://anglebug.com/2062)
2009 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsD3D11());
2010
Martin Radevc1d4e552017-08-21 12:01:10 +03002011 const std::string vsSource =
2012 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002013 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002014 "layout(num_views = 2) in;\n"
2015 "in vec3 vPosition;\n"
2016 "flat out int oInstanceID;\n"
2017 "void main()\n"
2018 "{\n"
2019 " gl_Position = vec4(vPosition, 1.);\n"
2020 " oInstanceID = gl_InstanceID;\n"
2021 "}\n";
2022
2023 const std::string fsSource =
2024 "#version 300 es\n"
Olli Etuahoec3a9cb2017-09-07 12:18:01 +03002025 "#extension GL_OVR_multiview : require\n"
Martin Radevc1d4e552017-08-21 12:01:10 +03002026 "precision mediump float;\n"
2027 "flat in int oInstanceID;\n"
2028 "out vec4 col;\n"
2029 "void main()\n"
2030 "{\n"
2031 " if (oInstanceID < 0) {\n"
2032 " discard;\n"
2033 " }\n"
2034 " if (gl_ViewID_OVR == 0u) {\n"
2035 " col = vec4(1,0,0,1);\n"
2036 " } else {\n"
2037 " col = vec4(0,1,0,1);\n"
2038 " }\n"
2039 "}\n";
2040
2041 createFBO(1, 1, 2);
2042 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2043
2044 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2045 ASSERT_GL_NO_ERROR();
2046
2047 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2048 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +03002049}
2050
Martin Radev265a6d42017-09-12 16:51:37 +03002051// The test is added to cover a bug which resulted in the viewport/scissor and viewport offsets not
2052// being correctly applied.
2053TEST_P(MultiviewSideBySideRenderTest, ViewportOffsetsAppliedBugCoverage)
2054{
2055 if (!requestMultiviewExtension())
2056 {
2057 return;
2058 }
2059
2060 createFBO(1, 1, 2);
2061
2062 // Create multiview program.
2063 const std::string &vs =
2064 "#version 300 es\n"
2065 "#extension GL_OVR_multiview : require\n"
2066 "layout(num_views = 2) in;\n"
2067 "layout(location = 0) in vec3 vPosition;\n"
2068 "void main()\n"
2069 "{\n"
2070 " gl_Position = vec4(vPosition, 1.0);\n"
2071 "}\n";
2072
2073 const std::string &fs =
2074 "#version 300 es\n"
2075 "#extension GL_OVR_multiview : require\n"
2076 "precision mediump float;\n"
2077 "out vec4 col;\n"
2078 "void main()\n"
2079 "{\n"
Martin Radev67a8a012017-09-08 13:03:52 +03002080 " col = vec4(0,1,0,1);\n"
Martin Radev265a6d42017-09-12 16:51:37 +03002081 "}\n";
2082
2083 ANGLE_GL_PROGRAM(program, vs, fs);
2084
2085 glViewport(0, 0, 1, 1);
2086 glScissor(0, 0, 1, 1);
2087 glEnable(GL_SCISSOR_TEST);
2088 glClearColor(0, 0, 0, 1);
2089
2090 // Bind the default FBO and make sure that the state is synchronized.
2091 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
2092 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2093 ASSERT_GL_NO_ERROR();
2094
2095 // Draw and check that both views are rendered to.
2096 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
2097 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev67a8a012017-09-08 13:03:52 +03002098
Martin Radev265a6d42017-09-12 16:51:37 +03002099 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
Martin Radev67a8a012017-09-08 13:03:52 +03002100 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
2101 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev265a6d42017-09-12 16:51:37 +03002102}
2103
Martin Radevc1d4e552017-08-21 12:01:10 +03002104MultiviewImplementationParams VertexShaderOpenGL()
Martin Radev3c25ad02017-08-22 17:36:53 +03002105{
Martin Radevc1d4e552017-08-21 12:01:10 +03002106 return MultiviewImplementationParams(false, egl_platform::OPENGL());
Martin Radev3c25ad02017-08-22 17:36:53 +03002107}
2108
Martin Radevc1d4e552017-08-21 12:01:10 +03002109MultiviewImplementationParams VertexShaderD3D11()
Martin Radev3c25ad02017-08-22 17:36:53 +03002110{
Martin Radevc1d4e552017-08-21 12:01:10 +03002111 return MultiviewImplementationParams(false, egl_platform::D3D11());
Martin Radev3c25ad02017-08-22 17:36:53 +03002112}
2113
Martin Radevc1d4e552017-08-21 12:01:10 +03002114MultiviewImplementationParams GeomShaderD3D11()
Martin Radev72b4e1e2017-08-31 15:42:56 +03002115{
Martin Radevc1d4e552017-08-21 12:01:10 +03002116 return MultiviewImplementationParams(true, egl_platform::D3D11());
2117}
2118
2119MultiviewTestParams SideBySideVertexShaderOpenGL()
2120{
2121 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, VertexShaderOpenGL());
2122}
2123
2124MultiviewTestParams LayeredVertexShaderOpenGL()
2125{
2126 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, VertexShaderOpenGL());
2127}
2128
2129MultiviewTestParams SideBySideGeomShaderD3D11()
2130{
2131 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, GeomShaderD3D11());
2132}
2133
2134MultiviewTestParams LayeredGeomShaderD3D11()
2135{
2136 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, GeomShaderD3D11());
2137}
2138
2139MultiviewTestParams SideBySideVertexShaderD3D11()
2140{
2141 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, VertexShaderD3D11());
2142}
2143
2144MultiviewTestParams LayeredVertexShaderD3D11()
2145{
2146 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, VertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002147}
2148
Martin Radev8f276e22017-05-30 12:05:52 +03002149ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest, ES31_OPENGL());
Martin Radevced5c862017-08-17 16:05:29 +03002150ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002151 SideBySideVertexShaderOpenGL(),
2152 LayeredVertexShaderOpenGL(),
2153 SideBySideGeomShaderD3D11(),
2154 SideBySideVertexShaderD3D11(),
2155 LayeredGeomShaderD3D11(),
2156 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002157ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002158 SideBySideVertexShaderOpenGL(),
2159 LayeredVertexShaderOpenGL(),
2160 SideBySideGeomShaderD3D11(),
2161 SideBySideVertexShaderD3D11(),
2162 LayeredGeomShaderD3D11(),
2163 LayeredVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002164ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002165 SideBySideVertexShaderOpenGL(),
2166 LayeredVertexShaderOpenGL(),
2167 SideBySideGeomShaderD3D11(),
2168 SideBySideVertexShaderD3D11(),
2169 LayeredGeomShaderD3D11(),
2170 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002171ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002172 SideBySideVertexShaderOpenGL(),
2173 LayeredVertexShaderOpenGL(),
2174 SideBySideGeomShaderD3D11(),
2175 SideBySideVertexShaderD3D11(),
2176 LayeredGeomShaderD3D11(),
2177 LayeredVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002178ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002179 SideBySideVertexShaderOpenGL(),
2180 LayeredVertexShaderOpenGL(),
2181 SideBySideGeomShaderD3D11(),
2182 SideBySideVertexShaderD3D11(),
2183 LayeredGeomShaderD3D11(),
2184 LayeredVertexShaderD3D11());
2185ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest, VertexShaderOpenGL(), GeomShaderD3D11());
2186ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, VertexShaderOpenGL(), GeomShaderD3D11());