blob: 4a39df0fb5ea307ee30315d96d7c8aa76cdcac21 [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"
40 " col = vec4(1,0,0,1);\n"
41 "}\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 Radev61bd9992017-08-11 13:10:55 +0300415 " col = vec4(1,0,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));
428 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
429 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
430 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 Radev3c25ad02017-08-22 17:36:53 +0300475 void checkRedChannel(const GLubyte expectedRedChannelData[])
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);
485 EXPECT_EQ(GLColor(expectedRedChannelData[flatIndex], 0, 0, 255),
486 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.
597// 3) does not generate any error if the program does not use the multiview extension.
598TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
599{
600 if (!requestMultiviewExtension())
601 {
602 return;
603 }
604
605 const GLint viewportOffsets[4] = {0, 0, 2, 0};
606
607 const std::string &vsSource =
608 "#version 300 es\n"
609 "#extension GL_OVR_multiview : require\n"
610 "layout(num_views = 2) in;\n"
611 "void main()\n"
612 "{}\n";
613 const std::string &fsSource =
614 "#version 300 es\n"
615 "#extension GL_OVR_multiview : require\n"
616 "precision mediump float;\n"
617 "void main()\n"
618 "{}\n";
619 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
620 glUseProgram(program);
621
622 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
623 // number of views.
624 {
625 // The framebuffer has only 1 view.
626 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
627 0, 1, &viewportOffsets[0]);
628
629 glDrawArrays(GL_TRIANGLES, 0, 3);
630 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
631
632 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
633 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
634 }
635
636 // Check that no errors are generated if the number of views in both program and draw
637 // framebuffer matches.
638 {
639 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
640 0, 2, &viewportOffsets[0]);
641
642 glDrawArrays(GL_TRIANGLES, 0, 3);
643 EXPECT_GL_NO_ERROR();
644
645 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
646 EXPECT_GL_NO_ERROR();
647 }
648
649 // Check that no errors are generated if the program does not use the multiview extension.
650 {
651 const std::string &vsSourceNoMultiview =
652 "#version 300 es\n"
653 "void main()\n"
654 "{}\n";
655 const std::string &fsSourceNoMultiview =
656 "#version 300 es\n"
657 "precision mediump float;\n"
658 "void main()\n"
659 "{}\n";
660 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
661 glUseProgram(programNoMultiview);
662
663 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
664 0, 2, &viewportOffsets[0]);
665
666 glDrawArrays(GL_TRIANGLES, 0, 3);
667 EXPECT_GL_NO_ERROR();
668
669 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
670 EXPECT_GL_NO_ERROR();
671 }
672}
673
Martin Radev7e69f762017-07-27 14:54:13 +0300674// The test verifies that glDraw*:
675// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
676// greater than 1 and there is an active transform feedback object.
677// 2) does not generate any error if the number of views in the draw framebuffer is 1.
678TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
679{
680 if (!requestMultiviewExtension())
681 {
682 return;
683 }
684
685 const GLint viewportOffsets[4] = {0, 0, 2, 0};
686
687 const std::string &vsSource =
688 "#version 300 es\n"
689 "void main()\n"
690 "{}\n";
691 const std::string &fsSource =
692 "#version 300 es\n"
693 "precision mediump float;\n"
694 "void main()\n"
695 "{}\n";
696 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
697 glUseProgram(program);
698
699 GLBuffer tbo;
700 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
701 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4u, nullptr, GL_STATIC_DRAW);
702
703 GLTransformFeedback transformFeedback;
704 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
705 glBeginTransformFeedback(GL_TRIANGLES);
706 ASSERT_GL_NO_ERROR();
707
708 // Check that drawArrays generates an error when there is an active transform feedback object
709 // and the number of views in the draw framebuffer is greater than 1.
710 {
711 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
712 0, 2, &viewportOffsets[0]);
713 glDrawArrays(GL_TRIANGLES, 0, 3);
714 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
715 }
716
717 // Check that drawArrays does not generate an error when the number of views in the draw
718 // framebuffer is 1.
719 {
720 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
721 0, 1, &viewportOffsets[0]);
722 glDrawArrays(GL_TRIANGLES, 0, 3);
723 EXPECT_GL_NO_ERROR();
724 }
725
726 glEndTransformFeedback();
727}
728
Martin Radevffe754b2017-07-31 10:38:07 +0300729// The test verifies that glDraw*:
730// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
731// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
732// 2) does not generate any error if the number of views in the draw framebuffer is 1.
733TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
734{
735 if (!requestMultiviewExtension())
736 {
737 return;
738 }
739
740 if (!extensionEnabled("GL_EXT_disjoint_timer_query"))
741 {
742 std::cout << "Test skipped because GL_EXT_disjoint_timer_query is not available."
743 << std::endl;
744 return;
745 }
746
747 const GLint viewportOffsets[4] = {0, 0, 2, 0};
748 const std::string &vsSource =
749 "#version 300 es\n"
750 "void main()\n"
751 "{}\n";
752 const std::string &fsSource =
753 "#version 300 es\n"
754 "precision mediump float;\n"
755 "void main()\n"
756 "{}\n";
757 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
758 glUseProgram(program);
759
760 GLuint query = 0u;
761 glGenQueriesEXT(1, &query);
762 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
763
764 // Check first case.
765 {
766 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
767 0, 2, &viewportOffsets[0]);
768 glDrawArrays(GL_TRIANGLES, 0, 3);
769 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
770 }
771
772 // Check second case.
773 {
774 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
775 0, 1, &viewportOffsets[0]);
776 glDrawArrays(GL_TRIANGLES, 0, 3);
777 EXPECT_GL_NO_ERROR();
778 }
779
780 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
781 glDeleteQueries(1, &query);
782}
783
Martin Radev8f276e22017-05-30 12:05:52 +0300784// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300785TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300786{
787 if (!requestMultiviewExtension())
788 {
789 return;
790 }
791 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
792 ASSERT_GL_NO_ERROR();
793
794 checkOutput();
795}
796
797// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300798TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300799{
800 if (!requestMultiviewExtension())
801 {
802 return;
803 }
804 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
805 ASSERT_GL_NO_ERROR();
806
807 checkOutput();
808}
809
810// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300811TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300812{
813 if (!requestMultiviewExtension())
814 {
815 return;
816 }
817 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
818 ASSERT_GL_NO_ERROR();
819
820 checkOutput();
821}
822
823// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300824TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300825{
826 if (!requestMultiviewExtension())
827 {
828 return;
829 }
830
831 const std::string vsSource =
832 "#version 300 es\n"
833 "#extension GL_OVR_multiview2 : require\n"
834 "layout(num_views = 4) in;\n"
835 "in vec4 vPosition;\n"
836 "void main()\n"
837 "{\n"
838 " if (gl_ViewID_OVR == 0u) {\n"
839 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
840 " } else if (gl_ViewID_OVR == 1u) {\n"
841 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
842 " } else if (gl_ViewID_OVR == 2u) {\n"
843 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
844 " } else {\n"
845 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
846 " }"
847 " gl_Position.yzw = vPosition.yzw;\n"
848 "}\n";
849
850 const std::string fsSource =
851 "#version 300 es\n"
852 "#extension GL_OVR_multiview2 : require\n"
853 "precision mediump float;\n"
854 "out vec4 col;\n"
855 "void main()\n"
856 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300857 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300858 "}\n";
859
Martin Radev3c25ad02017-08-22 17:36:53 +0300860 createFBO(4, 1, 4);
Martin Radev8f276e22017-05-30 12:05:52 +0300861 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
862 glUseProgram(program);
863
864 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
865 ASSERT_GL_NO_ERROR();
866
867 for (int i = 0; i < 4; ++i)
868 {
869 for (int j = 0; j < 4; ++j)
870 {
Martin Radev8f276e22017-05-30 12:05:52 +0300871 if (i == j)
872 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300873 EXPECT_EQ(GLColor::red, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300874 }
875 else
876 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300877 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300878 }
879 }
880 }
881 EXPECT_GL_NO_ERROR();
882}
883
884// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300885TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +0300886{
887 if (!requestMultiviewExtension())
888 {
889 return;
890 }
891
892 const std::string vsSource =
893 "#version 300 es\n"
894 "#extension GL_OVR_multiview : require\n"
895 "layout(num_views = 2) in;\n"
896 "in vec4 vPosition;\n"
897 "void main()\n"
898 "{\n"
899 " vec4 p = vPosition;\n"
900 " if (gl_InstanceID == 1){\n"
901 " p.y = .5*p.y + .5;\n"
902 " } else {\n"
903 " p.y = p.y*.5;\n"
904 " }\n"
905 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x*0.5 + 0.5 : p.x*0.5);\n"
906 " gl_Position.yzw = p.yzw;\n"
907 "}\n";
908
909 const std::string fsSource =
910 "#version 300 es\n"
911 "#extension GL_OVR_multiview : require\n"
912 "precision mediump float;\n"
913 "out vec4 col;\n"
914 "void main()\n"
915 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300916 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300917 "}\n";
918
Martin Radev3c25ad02017-08-22 17:36:53 +0300919 const int kViewWidth = 2;
920 const int kViewHeight = 2;
921 const int kNumViews = 2;
922 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev8f276e22017-05-30 12:05:52 +0300923 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
924 glUseProgram(program);
925
926 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 2);
927 ASSERT_GL_NO_ERROR();
928
Martin Radev3c25ad02017-08-22 17:36:53 +0300929 const GLubyte expectedRedChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
930 {{255, 0}, {255, 0}}};
931
932 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +0300933 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300934 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +0300935 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300936 for (int x = 0; x < 2; ++x)
937 {
938 EXPECT_EQ(GLColor(expectedRedChannel[view][y][x], 0, 0, 255),
939 GetViewColor(x, y, view));
940 }
Martin Radev8f276e22017-05-30 12:05:52 +0300941 }
942 }
943}
944
Martin Radev553590a2017-07-31 16:40:39 +0300945// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
946// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
947// offset of each quad are passed as separate attributes which are indexed based on the
948// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
949// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
950// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
951// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +0300952TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +0300953{
954 if (!requestMultiviewExtension())
955 {
956 return;
957 }
958
959 const std::string &vsSource =
960 "#version 300 es\n"
961 "#extension GL_OVR_multiview2 : require\n"
962 "layout(num_views = 2) in;\n"
963 "in vec3 vPosition;\n"
964 "in float offsetX;\n"
965 "in float offsetY;\n"
966 "void main()\n"
967 "{\n"
968 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +0300969 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300970 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
971 " gl_Position.yzw = p.yzw;\n"
972 "}\n";
973
974 const std::string &fsSource =
975 "#version 300 es\n"
976 "#extension GL_OVR_multiview2 : require\n"
977 "precision mediump float;\n"
978 "out vec4 col;\n"
979 "void main()\n"
980 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300981 " col = vec4(1,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300982 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +0300983
984 const int kViewWidth = 4;
985 const int kViewHeight = 4;
986 const int kNumViews = 2;
987 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev553590a2017-07-31 16:40:39 +0300988 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
989 glUseProgram(program);
990
991 GLBuffer xOffsetVBO;
992 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
993 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
994 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
995 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
996 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
997 glVertexAttribDivisor(xOffsetLoc, 3);
998 glEnableVertexAttribArray(xOffsetLoc);
999
1000 GLBuffer yOffsetVBO;
1001 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1002 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1003 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1004 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1005 glVertexAttribDivisor(yOffsetLoc, 1);
1006 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1007 glEnableVertexAttribArray(yOffsetLoc);
1008
1009 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
1010 ASSERT_GL_NO_ERROR();
1011
Martin Radev3c25ad02017-08-22 17:36:53 +03001012 const GLubyte expectedRedChannel[kNumViews][kViewHeight][kViewWidth] = {
1013 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1014 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1015 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +03001016 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001017 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +03001018 {
Martin Radev3c25ad02017-08-22 17:36:53 +03001019 for (int col = 0; col < 4; ++col)
1020 {
1021 EXPECT_EQ(GLColor(expectedRedChannel[view][row][col], 0, 0, 255),
1022 GetViewColor(col, row, view));
1023 }
Martin Radev553590a2017-07-31 16:40:39 +03001024 }
1025 }
1026}
1027
1028// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1029// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +03001030TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +03001031{
1032 if (!requestMultiviewExtension())
1033 {
1034 return;
1035 }
1036
Martin Radev3c25ad02017-08-22 17:36:53 +03001037 createFBO(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +03001038
1039 // Create multiview program.
1040 const std::string &vs =
1041 "#version 300 es\n"
1042 "#extension GL_OVR_multiview2 : require\n"
1043 "layout(num_views = 2) in;\n"
1044 "layout(location = 0) in vec2 vPosition;\n"
1045 "layout(location = 1) in float offsetX;\n"
1046 "void main()\n"
1047 "{\n"
1048 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1049 " p.x += offsetX;\n"
1050 " gl_Position = p;\n"
1051 "}\n";
1052
1053 const std::string &fs =
1054 "#version 300 es\n"
1055 "#extension GL_OVR_multiview2 : require\n"
1056 "precision mediump float;\n"
1057 "out vec4 col;\n"
1058 "void main()\n"
1059 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001060 " col = vec4(1,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001061 "}\n";
1062
1063 ANGLE_GL_PROGRAM(program, vs, fs);
1064
1065 const std::string &dummyVS =
1066 "#version 300 es\n"
1067 "layout(location = 0) in vec2 vPosition;\n"
1068 "layout(location = 1) in float offsetX;\n"
1069 "void main()\n"
1070 "{\n"
1071 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1072 "}\n";
1073
1074 const std::string &dummyFS =
1075 "#version 300 es\n"
1076 "precision mediump float;\n"
1077 "out vec4 col;\n"
1078 "void main()\n"
1079 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001080 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001081 "}\n";
1082
1083 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
1084
1085 GLBuffer xOffsetVBO;
1086 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1087 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1088 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1089 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1090
1091 GLBuffer vertexVBO;
1092 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1093 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1094 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1095 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1096
1097 GLVertexArray vao[2];
1098 for (size_t i = 0u; i < 2u; ++i)
1099 {
1100 glBindVertexArray(vao[i]);
1101
1102 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1103 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1104 glEnableVertexAttribArray(0);
1105
1106 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1107 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1108 glEnableVertexAttribArray(1);
1109 }
1110 ASSERT_GL_NO_ERROR();
1111
1112 glViewport(0, 0, 1, 1);
1113 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001114 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001115 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001116
1117 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1118 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1119 // bits are cleared.
1120 glUseProgram(dummyProgram);
1121 glBindVertexArray(vao[0]);
1122 glVertexAttribDivisor(1, 0);
1123 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1124 glUseProgram(0);
1125 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1126 ASSERT_GL_NO_ERROR();
1127
1128 // Check that vertexAttribDivisor uses the number of views to update the divisor.
1129 glUseProgram(program);
1130 glVertexAttribDivisor(1, 1);
1131 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001132 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1133 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001134
1135 // Clear the buffers and propagate divisor to the driver.
1136 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1137 // dirty bits when useProgram is called.
1138 glUseProgram(dummyProgram);
1139 glVertexAttribDivisor(1, 1);
1140 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1141 glUseProgram(0);
1142 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1143 ASSERT_GL_NO_ERROR();
1144
1145 // Check that useProgram uses the number of views to update the divisor.
1146 glUseProgram(program);
1147 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001148 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1149 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001150
1151 // We go through similar steps as before.
1152 glUseProgram(dummyProgram);
1153 glVertexAttribDivisor(1, 1);
1154 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1155 glUseProgram(0);
1156 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1157 ASSERT_GL_NO_ERROR();
1158
1159 // Check that bindVertexArray uses the number of views to update the divisor.
1160 {
1161 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1162 // divisor for vao[1] only.
1163 glBindVertexArray(vao[1]);
1164 glUseProgram(program);
1165 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1166 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1167 glBindVertexArray(0);
1168 ASSERT_GL_NO_ERROR();
1169 }
1170 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1171 // adjusts the divisor.
1172 glBindVertexArray(vao[0]);
1173 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001174 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1175 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001176}
1177
Martin Radev0d671c92017-08-10 16:41:52 +03001178// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1179// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001180TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001181{
1182 if (!requestMultiviewExtension())
1183 {
1184 return;
1185 }
1186
1187 const std::string vsSource =
1188 "#version 300 es\n"
1189 "#extension GL_OVR_multiview : require\n"
1190 "layout(num_views = 2) in;\n"
1191 "in vec3 vPosition;\n"
1192 "void main()\n"
1193 "{\n"
1194 " gl_Position.x = 2.0;\n"
1195 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1196 "}\n";
1197
1198 const std::string fsSource =
1199 "#version 300 es\n"
1200 "#extension GL_OVR_multiview : require\n"
1201 "precision mediump float;\n"
1202 "out vec4 col;\n"
1203 "void main()\n"
1204 "{\n"
1205 " col = vec4(1,0,0,0);\n"
1206 "}\n";
1207 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1208 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001209 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001210
1211 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1212 ASSERT_GL_NO_ERROR();
1213 EXPECT_GL_FALSE(result);
1214}
1215
1216// Test that there are fragments passing the occlusion query if only view 0 can produce
1217// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001218TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001219{
1220 if (!requestMultiviewExtension())
1221 {
1222 return;
1223 }
1224
1225 const std::string vsSource =
1226 "#version 300 es\n"
1227 "#extension GL_OVR_multiview : require\n"
1228 "layout(num_views = 2) in;\n"
1229 "in vec3 vPosition;\n"
1230 "void main()\n"
1231 "{\n"
1232 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1233 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1234 "}\n";
1235
1236 const std::string fsSource =
1237 "#version 300 es\n"
1238 "#extension GL_OVR_multiview : require\n"
1239 "precision mediump float;\n"
1240 "out vec4 col;\n"
1241 "void main()\n"
1242 "{\n"
1243 " col = vec4(1,0,0,0);\n"
1244 "}\n";
1245 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1246 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001247 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001248
1249 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1250 ASSERT_GL_NO_ERROR();
1251 EXPECT_GL_TRUE(result);
1252}
1253
1254// Test that there are fragments passing the occlusion query if only view 1 can produce
1255// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001256TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001257{
1258 if (!requestMultiviewExtension())
1259 {
1260 return;
1261 }
1262
1263 const std::string vsSource =
1264 "#version 300 es\n"
1265 "#extension GL_OVR_multiview : require\n"
1266 "layout(num_views = 2) in;\n"
1267 "in vec3 vPosition;\n"
1268 "void main()\n"
1269 "{\n"
1270 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1271 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1272 "}\n";
1273
1274 const std::string fsSource =
1275 "#version 300 es\n"
1276 "#extension GL_OVR_multiview : require\n"
1277 "precision mediump float;\n"
1278 "out vec4 col;\n"
1279 "void main()\n"
1280 "{\n"
1281 " col = vec4(1,0,0,0);\n"
1282 "}\n";
1283 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1284 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001285 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001286
1287 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1288 ASSERT_GL_NO_ERROR();
1289 EXPECT_GL_TRUE(result);
1290}
1291
Martin Radev41ac68e2017-06-06 12:16:58 +03001292// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1293// compiles and links without an error.
1294TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1295{
1296 if (!requestMultiviewExtension())
1297 {
1298 return;
1299 }
1300
1301 const std::string vsSource =
1302 "#version 300 es\n"
1303 "#extension GL_OVR_multiview : require\n"
1304 "layout(num_views = 2) in;\n"
1305 "void main()\n"
1306 "{\n"
1307 "}\n";
1308
1309 const std::string fsSource =
1310 "#version 300 es\n"
1311 "#extension GL_OVR_multiview : require\n"
1312 "precision mediump float;\n"
1313 "void main()\n"
1314 "{\n"
1315 "}\n";
1316
1317 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1318 glUseProgram(program);
1319
1320 EXPECT_GL_NO_ERROR();
1321}
1322
1323// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1324// without an error.
1325TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1326{
1327 if (!requestMultiviewExtension())
1328 {
1329 return;
1330 }
1331
1332 const std::string vsSource =
1333 "#version 300 es\n"
1334 "#extension GL_OVR_multiview2 : require\n"
1335 "layout(num_views = 2) in;\n"
1336 "void main()\n"
1337 "{\n"
1338 " if (gl_ViewID_OVR == 0u) {\n"
1339 " gl_Position = vec4(1,0,0,1);\n"
1340 " } else {\n"
1341 " gl_Position = vec4(-1,0,0,1);\n"
1342 " }\n"
1343 "}\n";
1344
1345 const std::string fsSource =
1346 "#version 300 es\n"
1347 "#extension GL_OVR_multiview2 : require\n"
1348 "precision mediump float;\n"
1349 "void main()\n"
1350 "{\n"
1351 "}\n";
1352
1353 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1354 glUseProgram(program);
1355
1356 EXPECT_GL_NO_ERROR();
1357}
1358
1359// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1360// without an error.
1361TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1362{
1363 if (!requestMultiviewExtension())
1364 {
1365 return;
1366 }
1367
1368 const std::string vsSource =
1369 "#version 300 es\n"
1370 "#extension GL_OVR_multiview2 : require\n"
1371 "layout(num_views = 2) in;\n"
1372 "void main()\n"
1373 "{\n"
1374 "}\n";
1375
1376 const std::string fsSource =
1377 "#version 300 es\n"
1378 "#extension GL_OVR_multiview2 : require\n"
1379 "precision mediump float;\n"
1380 "out vec4 col;\n"
1381 "void main()\n"
1382 "{\n"
1383 " if (gl_ViewID_OVR == 0u) {\n"
1384 " col = vec4(1,0,0,1);\n"
1385 " } else {\n"
1386 " col = vec4(-1,0,0,1);\n"
1387 " }\n"
1388 "}\n";
1389
1390 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1391 glUseProgram(program);
1392
1393 EXPECT_GL_NO_ERROR();
1394}
1395
Martin Radev61bd9992017-08-11 13:10:55 +03001396// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001397TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001398{
1399 if (!requestMultiviewExtension())
1400 {
1401 return;
1402 }
1403
1404 const std::string vsSource =
1405 "#version 300 es\n"
1406 "#extension GL_OVR_multiview : require\n"
1407 "layout(num_views = 2) in;\n"
1408 "layout(location=0) in vec2 vPosition;\n"
1409 "void main()\n"
1410 "{\n"
1411 " gl_PointSize = 1.0;\n"
1412 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1413 "}\n";
1414
1415 const std::string fsSource =
1416 "#version 300 es\n"
1417 "#extension GL_OVR_multiview : require\n"
1418 "precision mediump float;\n"
1419 "out vec4 col;\n"
1420 "void main()\n"
1421 "{\n"
1422 " col = vec4(1,0,0,1);\n"
1423 "}\n";
1424 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1425 glUseProgram(program);
1426
Martin Radev3c25ad02017-08-22 17:36:53 +03001427 const int kViewWidth = 4;
1428 const int kViewHeight = 2;
1429 const int kNumViews = 2;
1430 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001431
1432 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1433 std::vector<Vector2> vertexDataInClipSpace =
1434 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1435 setupGeometry(vertexDataInClipSpace);
1436
1437 glDrawArrays(GL_POINTS, 0, 2);
1438
Martin Radev3c25ad02017-08-22 17:36:53 +03001439 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1440 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
1441 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001442}
1443
1444// The test checks that GL_LINES is correctly rendered.
1445// The behavior of this test is not guaranteed by the spec:
1446// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1447// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1448// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1449// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001450TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001451{
1452 if (!requestMultiviewExtension())
1453 {
1454 return;
1455 }
1456
Martin Radevced5c862017-08-17 16:05:29 +03001457 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001458 ASSERT_NE(program, 0u);
1459 glUseProgram(program);
1460 ASSERT_GL_NO_ERROR();
1461
Martin Radev3c25ad02017-08-22 17:36:53 +03001462 const int kViewWidth = 4;
1463 const int kViewHeight = 2;
1464 const int kNumViews = 2;
1465 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001466
1467 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1468 std::vector<Vector2> vertexDataInClipSpace =
1469 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1470 setupGeometry(vertexDataInClipSpace);
1471
1472 glDrawArrays(GL_LINES, 0, 2);
1473
Martin Radev3c25ad02017-08-22 17:36:53 +03001474 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1475 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
1476 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001477
1478 glDeleteProgram(program);
1479}
1480
1481// The test checks that GL_LINE_STRIP is correctly rendered.
1482// The behavior of this test is not guaranteed by the spec:
1483// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1484// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1485// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1486// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001487TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001488{
1489 if (!requestMultiviewExtension())
1490 {
1491 return;
1492 }
1493
Martin Radevced5c862017-08-17 16:05:29 +03001494 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001495 ASSERT_NE(program, 0u);
1496 glUseProgram(program);
1497 ASSERT_GL_NO_ERROR();
1498
Martin Radev3c25ad02017-08-22 17:36:53 +03001499 const int kViewWidth = 4;
1500 const int kViewHeight = 2;
1501 const int kNumViews = 2;
1502 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001503
1504 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1505 std::vector<Vector2> vertexDataInClipSpace =
1506 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1507 setupGeometry(vertexDataInClipSpace);
1508
1509 glDrawArrays(GL_LINE_STRIP, 0, 3);
1510
Martin Radev3c25ad02017-08-22 17:36:53 +03001511 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1512 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
1513 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001514
1515 glDeleteProgram(program);
1516}
1517
1518// The test checks that GL_LINE_LOOP is correctly rendered.
1519// The behavior of this test is not guaranteed by the spec:
1520// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1521// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1522// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1523// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001524TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001525{
1526 if (!requestMultiviewExtension())
1527 {
1528 return;
1529 }
1530
Martin Radevced5c862017-08-17 16:05:29 +03001531 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001532 ASSERT_NE(program, 0u);
1533 glUseProgram(program);
1534 ASSERT_GL_NO_ERROR();
1535
Martin Radev3c25ad02017-08-22 17:36:53 +03001536 const int kViewWidth = 4;
1537 const int kViewHeight = 4;
1538 const int kNumViews = 2;
1539 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001540
1541 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1542 Vector2I(0, 3)};
1543 std::vector<Vector2> vertexDataInClipSpace =
1544 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1545 setupGeometry(vertexDataInClipSpace);
1546
1547 glDrawArrays(GL_LINE_LOOP, 0, 4);
1548
Martin Radev3c25ad02017-08-22 17:36:53 +03001549 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1550 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1551 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
1552 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001553
1554 glDeleteProgram(program);
1555}
1556
1557// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001558TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001559{
1560 if (!requestMultiviewExtension())
1561 {
1562 return;
1563 }
1564
Martin Radevced5c862017-08-17 16:05:29 +03001565 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001566 ASSERT_NE(program, 0u);
1567 glUseProgram(program);
1568 ASSERT_GL_NO_ERROR();
1569
1570 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1571 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1572 setupGeometry(vertexDataInClipSpace);
1573
Martin Radev3c25ad02017-08-22 17:36:53 +03001574 const int kViewWidth = 2;
1575 const int kViewHeight = 2;
1576 const int kNumViews = 2;
1577 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001578
1579 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1580
Martin Radev3c25ad02017-08-22 17:36:53 +03001581 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {{{0, 0}, {0, 255}},
1582 {{0, 0}, {0, 255}}};
1583 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001584
1585 glDeleteProgram(program);
1586}
1587
1588// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001589TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001590{
1591 if (!requestMultiviewExtension())
1592 {
1593 return;
1594 }
1595
Martin Radevced5c862017-08-17 16:05:29 +03001596 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001597 ASSERT_NE(program, 0u);
1598 glUseProgram(program);
1599 ASSERT_GL_NO_ERROR();
1600
1601 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1602 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1603 setupGeometry(vertexDataInClipSpace);
1604
Martin Radev3c25ad02017-08-22 17:36:53 +03001605 const int kViewWidth = 2;
1606 const int kViewHeight = 2;
1607 const int kNumViews = 2;
1608 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001609
1610 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1611
Martin Radev3c25ad02017-08-22 17:36:53 +03001612 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {{{0, 0}, {0, 255}},
1613 {{0, 0}, {0, 255}}};
1614 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001615
1616 glDeleteProgram(program);
1617}
1618
1619// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1620// bounds. The test does not rely on the actual line width being greater than 1.0.
Martin Radev3c25ad02017-08-22 17:36:53 +03001621TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
Martin Radev61bd9992017-08-11 13:10:55 +03001622{
1623 if (!requestMultiviewExtension())
1624 {
1625 return;
1626 }
1627
Martin Radev3c25ad02017-08-22 17:36:53 +03001628 createFBO(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +03001629
1630 GLint viewportOffsets[4] = {1, 0, 3, 0};
1631 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1632 mColorTexture, 0, 2, &viewportOffsets[0]);
1633 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
1634 mDepthTexture, 0, 2, &viewportOffsets[0]);
1635
1636 glViewport(0, 0, 1, 1);
1637 glScissor(0, 0, 1, 1);
1638 glEnable(GL_SCISSOR_TEST);
1639
1640 const std::string vsSource =
1641 "#version 300 es\n"
1642 "#extension GL_OVR_multiview2 : require\n"
1643 "layout(num_views = 2) in;\n"
1644 "layout(location=0) in vec2 vPosition;\n"
1645 "void main()\n"
1646 "{\n"
1647 " gl_PointSize = 10.0;\n"
1648 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1649 "}\n";
1650
1651 const std::string fsSource =
1652 "#version 300 es\n"
1653 "#extension GL_OVR_multiview2 : require\n"
1654 "precision mediump float;\n"
1655 "out vec4 col;\n"
1656 "void main()\n"
1657 "{\n"
1658 " if (gl_ViewID_OVR == 0u) {\n"
1659 " col = vec4(1,0,0,1);\n"
1660 " } else {\n"
1661 " col = vec4(0,1,0,1);\n"
1662 " }\n"
1663 "}\n";
1664 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1665 glUseProgram(program);
1666
1667 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1668 const std::vector<Vector2> &vertexDataInClipSpace =
1669 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001670
1671 GLBuffer vbo;
1672 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1673 glBufferData(GL_ARRAY_BUFFER, vertexDataInClipSpace.size() * sizeof(Vector2),
1674 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1675 glEnableVertexAttribArray(0);
1676 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
Martin Radev61bd9992017-08-11 13:10:55 +03001677
1678 // Test rendering points.
1679 {
1680 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1681 glDrawArrays(GL_POINTS, 0, 2);
1682 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1683 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1684 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1685 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1686 }
1687
1688 // Test rendering lines.
1689 {
1690 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1691 glLineWidth(10.f);
1692 glDrawArrays(GL_LINES, 0, 2);
1693 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1694 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1695 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1696 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1697 }
1698}
1699
Martin Radev0abb7a22017-08-28 15:34:45 +03001700// Verify that re-linking a program adjusts the attribute divisor.
1701// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1702// to each other. The quads' position and color depend on the corresponding attribute divisors.
1703TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1704{
1705 if (!requestMultiviewExtension())
1706 {
1707 return;
1708 }
1709
1710 const int kViewWidth = 4;
1711 const int kViewHeight = 1;
1712 const int kNumViews = 2;
1713
1714 const std::string &fsSource =
1715 "#version 300 es\n"
1716 "#extension GL_OVR_multiview2 : require\n"
1717 "precision mediump float;\n"
1718 "in vec4 oColor;\n"
1719 "out vec4 col;\n"
1720 "void main()\n"
1721 "{\n"
1722 " col = oColor;\n"
1723 "}\n";
1724
1725 auto generateVertexShaderSource = [](int numViews) -> std::string {
1726 std::string source =
1727 "#version 300 es\n"
1728 "#extension GL_OVR_multiview2 : require\n"
1729 "layout(num_views = " +
1730 ToString(numViews) +
1731 ") in;\n"
1732 "in vec3 vPosition;\n"
1733 "in float vOffsetX;\n"
1734 "in vec4 vColor;\n"
1735 "out vec4 oColor;\n"
1736 "void main()\n"
1737 "{\n"
1738 " vec4 p = vec4(vPosition, 1.);\n"
1739 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1740 " oColor = vColor;\n"
1741 " gl_Position = p;\n"
1742 "}\n";
1743 return source;
1744 };
1745
1746 std::string vsSource = generateVertexShaderSource(kNumViews);
1747 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1748 glUseProgram(program);
1749
1750 GLint positionLoc;
1751 GLBuffer xOffsetVBO;
1752 GLint xOffsetLoc;
1753 GLBuffer colorVBO;
1754 GLint colorLoc;
1755
1756 {
1757 // Initialize buffers and setup attributes.
1758 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1759 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1760 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1761 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1762 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1763 glVertexAttribDivisor(xOffsetLoc, 1);
1764 glEnableVertexAttribArray(xOffsetLoc);
1765
1766 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1767 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1768 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1769 colorLoc = glGetAttribLocation(program, "vColor");
1770 glVertexAttribDivisor(colorLoc, 2);
1771 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1772 glEnableVertexAttribArray(colorLoc);
1773
1774 positionLoc = glGetAttribLocation(program, "vPosition");
1775 }
1776
1777 {
1778 createFBO(kViewWidth, kViewHeight, kNumViews);
1779
1780 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
1781 ASSERT_GL_NO_ERROR();
1782
1783 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1784 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1785 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1786 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1787 }
1788
1789 {
1790 const int kNewNumViews = 3;
1791 vsSource = generateVertexShaderSource(kNewNumViews);
1792 createFBO(kViewWidth, kViewHeight, kNewNumViews);
1793
1794 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
1795 ASSERT_NE(0u, vs);
1796 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
1797 ASSERT_NE(0u, fs);
1798
1799 GLint numAttachedShaders = 0;
1800 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1801
1802 GLuint attachedShaders[2] = {0u};
1803 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1804 for (int i = 0; i < 2; ++i)
1805 {
1806 glDetachShader(program, attachedShaders[i]);
1807 }
1808
1809 glAttachShader(program, vs);
1810 glDeleteShader(vs);
1811
1812 glAttachShader(program, fs);
1813 glDeleteShader(fs);
1814
1815 glBindAttribLocation(program, positionLoc, "vPosition");
1816 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1817 glBindAttribLocation(program, colorLoc, "vColor");
1818
1819 glLinkProgram(program);
1820
1821 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
1822 ASSERT_GL_NO_ERROR();
1823
1824 for (int i = 0; i < kNewNumViews; ++i)
1825 {
1826 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1827 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1828 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1829 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1830 }
1831 }
1832}
1833
Martin Radevced5c862017-08-17 16:05:29 +03001834// Test that useProgram applies the number of views in computing the final value of the attribute
1835// divisor.
1836TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1837{
1838 if (!requestMultiviewExtension())
1839 {
1840 return;
1841 }
1842
1843 GLVertexArray vao;
1844 glBindVertexArray(vao);
1845 GLBuffer vbo;
1846 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1847 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
1848 Vector2I(3, 0)};
1849 std::vector<Vector2> vertexDataInClipSpace =
1850 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
1851 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
1852 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
1853 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1854 glEnableVertexAttribArray(0);
1855 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
1856 glVertexAttribDivisor(0, 1);
1857 ASSERT_GL_NO_ERROR();
1858
1859 // Create a program and fbo with N views and draw N instances of a point horizontally.
1860 for (int numViews = 2; numViews <= 4; ++numViews)
1861 {
1862 createFBO(4, 1, numViews);
1863 ASSERT_GL_NO_ERROR();
1864
1865 GLuint program = CreateSimplePassthroughProgram(numViews);
1866 ASSERT_NE(program, 0u);
1867 glUseProgram(program);
1868 ASSERT_GL_NO_ERROR();
1869
1870 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
1871
1872 for (int view = 0; view < numViews; ++view)
1873 {
1874 for (int j = 0; j < numViews; ++j)
1875 {
1876 EXPECT_EQ(GLColor::red, GetViewColor(j, 0, view));
1877 }
1878 for (int j = numViews; j < 4; ++j)
1879 {
1880 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, view));
1881 }
1882 }
1883
1884 glDeleteProgram(program);
1885 }
1886}
1887
Martin Radev72b4e1e2017-08-31 15:42:56 +03001888// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
1889TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
1890{
1891 if (!requestMultiviewExtension())
1892 {
1893 return;
1894 }
1895
1896 const std::string vsSource =
1897 "#version 300 es\n"
1898 "#extension GL_OVR_multiview2 : require\n"
1899 "layout(num_views = 3) in;\n"
1900 "in vec3 vPosition;\n"
1901 "void main()\n"
1902 "{\n"
1903 " gl_Position = vec4(vPosition, 1.);\n"
1904 "}\n";
1905
1906 const std::string fsSource =
1907 "#version 300 es\n"
1908 "#extension GL_OVR_multiview2 : require\n"
1909 "precision mediump float;\n"
1910 "out vec4 col;\n"
1911 "void main()\n"
1912 "{\n"
1913 " if (gl_ViewID_OVR == 0u) {\n"
1914 " col = vec4(1,0,0,1);\n"
1915 " } else if (gl_ViewID_OVR == 1u) {\n"
1916 " col = vec4(0,1,0,1);\n"
1917 " } else if (gl_ViewID_OVR == 2u) {\n"
1918 " col = vec4(0,0,1,1);\n"
1919 " } else {\n"
1920 " col = vec4(0,0,0,0);\n"
1921 " }\n"
1922 "}\n";
1923
1924 createFBO(1, 1, 3);
1925 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1926 glUseProgram(program);
1927
1928 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1929 ASSERT_GL_NO_ERROR();
1930
1931 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1932 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1933 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
1934}
1935
1936// The test checks that the inactive layers of a 2D texture array are not written to by a
1937// multi-view program.
1938TEST_P(MultiviewLayeredRenderTest, RenderToSubrageOfLayers)
1939{
1940 if (!requestMultiviewExtension())
1941 {
1942 return;
1943 }
1944
1945 const std::string vsSource =
1946 "#version 300 es\n"
1947 "#extension GL_OVR_multiview : require\n"
1948 "layout(num_views = 2) in;\n"
1949 "in vec3 vPosition;\n"
1950 "void main()\n"
1951 "{\n"
1952 " gl_Position = vec4(vPosition, 1.);\n"
1953 "}\n";
1954
1955 const std::string fsSource =
1956 "#version 300 es\n"
1957 "#extension GL_OVR_multiview : require\n"
1958 "precision mediump float;\n"
1959 "out vec4 col;\n"
1960 "void main()\n"
1961 "{\n"
1962 " col = vec4(1,0,0,1);\n"
1963 "}\n";
1964
1965 createFBO(1, 1, 2, 4, 1);
1966 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1967 glUseProgram(program);
1968
1969 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1970 ASSERT_GL_NO_ERROR();
1971
1972 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
1973 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
1974 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 2));
1975 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
1976}
1977
Martin Radevc1d4e552017-08-21 12:01:10 +03001978// The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
1979// potential bugs if the view is selected in the VS. The test contains a program in which the
1980// gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
1981// fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
1982// never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
1983// green for view 1.
1984TEST_P(MultiviewRenderTest, FlatInterpolation)
Martin Radev3c25ad02017-08-22 17:36:53 +03001985{
Martin Radevc1d4e552017-08-21 12:01:10 +03001986 if (!requestMultiviewExtension())
1987 {
1988 return;
1989 }
1990
Yuly Novikov1de29ab2017-09-07 18:07:23 -04001991 // TODO(mradev): Find out why this fails on Win10 Intel HD 630 D3D11
1992 // (http://anglebug.com/2062)
1993 ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsD3D11());
1994
Martin Radevc1d4e552017-08-21 12:01:10 +03001995 const std::string vsSource =
1996 "#version 300 es\n"
1997 "#extension GL_OVR_multiview2 : require\n"
1998 "layout(num_views = 2) in;\n"
1999 "in vec3 vPosition;\n"
2000 "flat out int oInstanceID;\n"
2001 "void main()\n"
2002 "{\n"
2003 " gl_Position = vec4(vPosition, 1.);\n"
2004 " oInstanceID = gl_InstanceID;\n"
2005 "}\n";
2006
2007 const std::string fsSource =
2008 "#version 300 es\n"
2009 "#extension GL_OVR_multiview2 : require\n"
2010 "precision mediump float;\n"
2011 "flat in int oInstanceID;\n"
2012 "out vec4 col;\n"
2013 "void main()\n"
2014 "{\n"
2015 " if (oInstanceID < 0) {\n"
2016 " discard;\n"
2017 " }\n"
2018 " if (gl_ViewID_OVR == 0u) {\n"
2019 " col = vec4(1,0,0,1);\n"
2020 " } else {\n"
2021 " col = vec4(0,1,0,1);\n"
2022 " }\n"
2023 "}\n";
2024
2025 createFBO(1, 1, 2);
2026 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
2027
2028 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2029 ASSERT_GL_NO_ERROR();
2030
2031 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2032 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
Martin Radev3c25ad02017-08-22 17:36:53 +03002033}
2034
Martin Radevc1d4e552017-08-21 12:01:10 +03002035MultiviewImplementationParams VertexShaderOpenGL()
Martin Radev3c25ad02017-08-22 17:36:53 +03002036{
Martin Radevc1d4e552017-08-21 12:01:10 +03002037 return MultiviewImplementationParams(false, egl_platform::OPENGL());
Martin Radev3c25ad02017-08-22 17:36:53 +03002038}
2039
Martin Radevc1d4e552017-08-21 12:01:10 +03002040MultiviewImplementationParams VertexShaderD3D11()
Martin Radev3c25ad02017-08-22 17:36:53 +03002041{
Martin Radevc1d4e552017-08-21 12:01:10 +03002042 return MultiviewImplementationParams(false, egl_platform::D3D11());
Martin Radev3c25ad02017-08-22 17:36:53 +03002043}
2044
Martin Radevc1d4e552017-08-21 12:01:10 +03002045MultiviewImplementationParams GeomShaderD3D11()
Martin Radev72b4e1e2017-08-31 15:42:56 +03002046{
Martin Radevc1d4e552017-08-21 12:01:10 +03002047 return MultiviewImplementationParams(true, egl_platform::D3D11());
2048}
2049
2050MultiviewTestParams SideBySideVertexShaderOpenGL()
2051{
2052 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, VertexShaderOpenGL());
2053}
2054
2055MultiviewTestParams LayeredVertexShaderOpenGL()
2056{
2057 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, VertexShaderOpenGL());
2058}
2059
2060MultiviewTestParams SideBySideGeomShaderD3D11()
2061{
2062 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, GeomShaderD3D11());
2063}
2064
2065MultiviewTestParams LayeredGeomShaderD3D11()
2066{
2067 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, GeomShaderD3D11());
2068}
2069
2070MultiviewTestParams SideBySideVertexShaderD3D11()
2071{
2072 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, VertexShaderD3D11());
2073}
2074
2075MultiviewTestParams LayeredVertexShaderD3D11()
2076{
2077 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, VertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002078}
2079
Martin Radev8f276e22017-05-30 12:05:52 +03002080ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest, ES31_OPENGL());
Martin Radevced5c862017-08-17 16:05:29 +03002081ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002082 SideBySideVertexShaderOpenGL(),
2083 LayeredVertexShaderOpenGL(),
2084 SideBySideGeomShaderD3D11(),
2085 SideBySideVertexShaderD3D11(),
2086 LayeredGeomShaderD3D11(),
2087 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002088ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002089 SideBySideVertexShaderOpenGL(),
2090 LayeredVertexShaderOpenGL(),
2091 SideBySideGeomShaderD3D11(),
2092 SideBySideVertexShaderD3D11(),
2093 LayeredGeomShaderD3D11(),
2094 LayeredVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002095ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002096 SideBySideVertexShaderOpenGL(),
2097 LayeredVertexShaderOpenGL(),
2098 SideBySideGeomShaderD3D11(),
2099 SideBySideVertexShaderD3D11(),
2100 LayeredGeomShaderD3D11(),
2101 LayeredVertexShaderD3D11());
Martin Radev72b4e1e2017-08-31 15:42:56 +03002102ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002103 SideBySideVertexShaderOpenGL(),
2104 LayeredVertexShaderOpenGL(),
2105 SideBySideGeomShaderD3D11(),
2106 SideBySideVertexShaderD3D11(),
2107 LayeredGeomShaderD3D11(),
2108 LayeredVertexShaderD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03002109ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
Martin Radevc1d4e552017-08-21 12:01:10 +03002110 SideBySideVertexShaderOpenGL(),
2111 LayeredVertexShaderOpenGL(),
2112 SideBySideGeomShaderD3D11(),
2113 SideBySideVertexShaderD3D11(),
2114 LayeredGeomShaderD3D11(),
2115 LayeredVertexShaderD3D11());
2116ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest, VertexShaderOpenGL(), GeomShaderD3D11());
2117ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, VertexShaderOpenGL(), GeomShaderD3D11());