blob: 9d9e14b3d0331d20b5266f979b699cfce890e78e [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
10#include "test_utils/ANGLETest.h"
11#include "test_utils/gl_raii.h"
12
13using namespace angle;
14
Martin Radev61bd9992017-08-11 13:10:55 +030015namespace
16{
Martin Radevced5c862017-08-17 16:05:29 +030017GLuint CreateSimplePassthroughProgram(int numViews)
Martin Radev61bd9992017-08-11 13:10:55 +030018{
19 const std::string vsSource =
20 "#version 300 es\n"
21 "#extension GL_OVR_multiview : require\n"
Martin Radevced5c862017-08-17 16:05:29 +030022 "layout(num_views = " +
23 ToString(numViews) +
24 ") in;\n"
Martin Radev61bd9992017-08-11 13:10:55 +030025 "layout(location=0) in vec2 vPosition;\n"
26 "void main()\n"
27 "{\n"
Martin Radevced5c862017-08-17 16:05:29 +030028 " gl_PointSize = 1.;\n"
Martin Radev61bd9992017-08-11 13:10:55 +030029 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
30 "}\n";
31
32 const std::string fsSource =
33 "#version 300 es\n"
34 "#extension GL_OVR_multiview : require\n"
35 "precision mediump float;\n"
36 "out vec4 col;\n"
37 "void main()\n"
38 "{\n"
39 " col = vec4(1,0,0,1);\n"
40 "}\n";
41 return CompileProgram(vsSource, fsSource);
42}
43
44std::vector<Vector2> ConvertPixelCoordinatesToClipSpace(const std::vector<Vector2I> &pixels,
45 int width,
46 int height)
47{
48 std::vector<Vector2> result(pixels.size());
49 for (size_t i = 0; i < pixels.size(); ++i)
50 {
51 const auto &pixel = pixels[i];
52 float pixelCenterRelativeX = (static_cast<float>(pixel.x()) + .5f) / width;
53 float pixelCenterRelativeY = (static_cast<float>(pixel.y()) + .5f) / height;
54 float xInClipSpace = 2.f * pixelCenterRelativeX - 1.f;
55 float yInClipSpace = 2.f * pixelCenterRelativeY - 1.f;
56 result[i] = Vector2(xInClipSpace, yInClipSpace);
57 }
58 return result;
59}
60} // namespace
61
Martin Radev3c25ad02017-08-22 17:36:53 +030062struct MultiviewTestParams final : public PlatformParameters
63{
64 MultiviewTestParams(GLenum multiviewLayout, const EGLPlatformParameters &eglPlatformParameters)
65 : PlatformParameters(3, 0, eglPlatformParameters), mMultiviewLayout(multiviewLayout)
66 {
67 ASSERT(multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE ||
68 multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
69 }
70 GLenum mMultiviewLayout;
71};
72
73std::ostream &operator<<(std::ostream &os, const MultiviewTestParams &params)
74{
75 const PlatformParameters &base = static_cast<const PlatformParameters &>(params);
76 os << base;
77 switch (params.mMultiviewLayout)
78 {
79 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
80 os << "_layered";
81 break;
82 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
83 os << "_side_by_side";
84 break;
85 default:
86 UNREACHABLE();
87 }
88 return os;
89}
90
91class MultiviewDrawTest : public ANGLETestBase
Martin Radev14a26ae2017-07-24 15:56:29 +030092{
93 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +030094 MultiviewDrawTest(const PlatformParameters &params) : ANGLETestBase(params)
Martin Radev14a26ae2017-07-24 15:56:29 +030095 {
96 setWindowWidth(128);
97 setWindowHeight(128);
98 setWebGLCompatibilityEnabled(true);
99 }
Martin Radev7cf61662017-07-26 17:10:53 +0300100 virtual ~MultiviewDrawTest() {}
Martin Radev14a26ae2017-07-24 15:56:29 +0300101
Martin Radev3c25ad02017-08-22 17:36:53 +0300102 void DrawTestSetUp()
Martin Radev14a26ae2017-07-24 15:56:29 +0300103 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300104 ANGLETestBase::ANGLETestSetUp();
Martin Radev14a26ae2017-07-24 15:56:29 +0300105
106 glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
107 eglGetProcAddress("glRequestExtensionANGLE"));
108 }
109
110 // Requests the ANGLE_multiview extension and returns true if the operation succeeds.
111 bool requestMultiviewExtension()
112 {
113 if (extensionRequestable("GL_ANGLE_multiview"))
114 {
115 glRequestExtensionANGLE("GL_ANGLE_multiview");
116 }
117
118 if (!extensionEnabled("GL_ANGLE_multiview"))
119 {
120 std::cout << "Test skipped due to missing GL_ANGLE_multiview." << std::endl;
121 return false;
122 }
123 return true;
124 }
125
126 PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
127};
128
Martin Radev3c25ad02017-08-22 17:36:53 +0300129class MultiviewDrawValidationTest : public MultiviewDrawTest,
130 public ::testing::TestWithParam<PlatformParameters>
Martin Radev7cf61662017-07-26 17:10:53 +0300131{
132 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300133 MultiviewDrawValidationTest() : MultiviewDrawTest(GetParam()) {}
Martin Radev7cf61662017-07-26 17:10:53 +0300134
135 void SetUp() override
136 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300137 MultiviewDrawTest::DrawTestSetUp();
Martin Radev7cf61662017-07-26 17:10:53 +0300138
139 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
140
141 glBindTexture(GL_TEXTURE_2D, mTex2d);
142 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
143
144 glBindVertexArray(mVao);
145
146 const float kVertexData[3] = {0.0f};
147 glBindBuffer(GL_ARRAY_BUFFER, mVbo);
148 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
149
150 const unsigned int kIndices[3] = {0u, 1u, 2u};
151 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo);
152 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
153 GL_STATIC_DRAW);
154 ASSERT_GL_NO_ERROR();
155 }
156
157 GLTexture mTex2d;
158 GLVertexArray mVao;
159 GLBuffer mVbo;
160 GLBuffer mIbo;
161 GLFramebuffer mFramebuffer;
162};
163
Martin Radev3c25ad02017-08-22 17:36:53 +0300164class MultiviewRenderTestBase : public MultiviewDrawTest
Martin Radev8f276e22017-05-30 12:05:52 +0300165{
166 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300167 MultiviewRenderTestBase(const PlatformParameters &params, GLenum multiviewLayout)
168 : MultiviewDrawTest(params),
169 mMultiviewLayout(multiviewLayout),
170 mViewWidth(0),
171 mViewHeight(0),
172 mNumViews(0)
Martin Radev8f276e22017-05-30 12:05:52 +0300173 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300174 }
175 void RenderTestSetUp() { MultiviewDrawTest::DrawTestSetUp(); }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300176 void createFBO(int viewWidth, int height, int numViews, int numLayers, int baseViewIndex)
Martin Radev3c25ad02017-08-22 17:36:53 +0300177 {
Martin Radev72b4e1e2017-08-31 15:42:56 +0300178 ASSERT(numViews + baseViewIndex <= numLayers);
179
Martin Radev3c25ad02017-08-22 17:36:53 +0300180 mViewWidth = viewWidth;
181 mViewHeight = height;
182 mNumViews = numViews;
Martin Radev8f276e22017-05-30 12:05:52 +0300183
Martin Radev0abb7a22017-08-28 15:34:45 +0300184 mColorTexture.reset();
185 mDepthTexture.reset();
186 mDrawFramebuffer.reset();
187 mReadFramebuffer.clear();
188
Martin Radev8f276e22017-05-30 12:05:52 +0300189 // Create color and depth textures.
Martin Radev3c25ad02017-08-22 17:36:53 +0300190 switch (mMultiviewLayout)
Martin Radev8f276e22017-05-30 12:05:52 +0300191 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300192 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
193 {
194 int textureWidth = viewWidth * numViews;
195 glBindTexture(GL_TEXTURE_2D, mColorTexture);
196 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, height, 0, GL_RGBA,
197 GL_UNSIGNED_BYTE, NULL);
198 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
199 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
200
201 glBindTexture(GL_TEXTURE_2D, mDepthTexture);
202 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, textureWidth, height, 0,
203 GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
204 glBindTexture(GL_TEXTURE_2D, 0);
205 break;
206 }
207 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
208 glBindTexture(GL_TEXTURE_2D_ARRAY, mColorTexture);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300209 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, viewWidth, height, numLayers, 0,
Martin Radev3c25ad02017-08-22 17:36:53 +0300210 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
211 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
212 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
213
214 glBindTexture(GL_TEXTURE_2D_ARRAY, mDepthTexture);
215 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, viewWidth, height,
Martin Radev72b4e1e2017-08-31 15:42:56 +0300216 numLayers, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
Martin Radev3c25ad02017-08-22 17:36:53 +0300217 glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
218 break;
219 default:
220 UNREACHABLE();
Martin Radev8f276e22017-05-30 12:05:52 +0300221 }
Martin Radev3c25ad02017-08-22 17:36:53 +0300222 ASSERT_GL_NO_ERROR();
223
224 // Create draw framebuffer to be used for multiview rendering.
225 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
226 switch (mMultiviewLayout)
227 {
228 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
229 {
230 std::vector<GLint> viewportOffsets(numViews * 2);
231 for (int i = 0u; i < numViews; ++i)
232 {
233 viewportOffsets[i * 2] = i * viewWidth;
234 viewportOffsets[i * 2 + 1] = 0;
235 }
236 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER,
237 GL_COLOR_ATTACHMENT0, mColorTexture, 0,
238 numViews, &viewportOffsets[0]);
239 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER,
240 GL_DEPTH_ATTACHMENT, mDepthTexture, 0,
241 numViews, &viewportOffsets[0]);
242 break;
243 }
244 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
245 glFramebufferTextureMultiviewLayeredANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
Martin Radev72b4e1e2017-08-31 15:42:56 +0300246 mColorTexture, 0, baseViewIndex,
247 numViews);
Martin Radev3c25ad02017-08-22 17:36:53 +0300248 glFramebufferTextureMultiviewLayeredANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
Martin Radev72b4e1e2017-08-31 15:42:56 +0300249 mDepthTexture, 0, baseViewIndex,
250 numViews);
Martin Radev3c25ad02017-08-22 17:36:53 +0300251 break;
252 default:
253 UNREACHABLE();
254 }
Martin Radev8f276e22017-05-30 12:05:52 +0300255
256 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
257 glDrawBuffers(1, DrawBuffers);
258 ASSERT_GL_NO_ERROR();
259 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
260
261 // Create read framebuffer to be used to retrieve the pixel information for testing
262 // purposes.
Martin Radev3c25ad02017-08-22 17:36:53 +0300263 switch (mMultiviewLayout)
264 {
265 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
266 mReadFramebuffer.resize(1);
267 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[0]);
268 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
269 mColorTexture, 0);
Martin Radev72b4e1e2017-08-31 15:42:56 +0300270 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
271 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300272 break;
273 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
Martin Radev72b4e1e2017-08-31 15:42:56 +0300274 mReadFramebuffer.resize(numLayers);
275 for (int i = 0; i < numLayers; ++i)
Martin Radev3c25ad02017-08-22 17:36:53 +0300276 {
Martin Radev72b4e1e2017-08-31 15:42:56 +0300277 glBindFramebuffer(GL_FRAMEBUFFER, mReadFramebuffer[i]);
278 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mColorTexture,
279 0, i);
280 glClearColor(0, 0, 0, 0);
281 glClear(GL_COLOR_BUFFER_BIT);
282 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
283 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
Martin Radev3c25ad02017-08-22 17:36:53 +0300284 }
Martin Radev72b4e1e2017-08-31 15:42:56 +0300285 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
Martin Radev3c25ad02017-08-22 17:36:53 +0300286 break;
287 default:
288 UNREACHABLE();
289 }
Martin Radev8f276e22017-05-30 12:05:52 +0300290
291 // Clear the buffers.
Martin Radev3c25ad02017-08-22 17:36:53 +0300292 glViewport(0, 0, viewWidth, height);
293 if (mMultiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
294 {
295 // Enable the scissor test only for side-by-side framebuffers.
296 glEnable(GL_SCISSOR_TEST);
297 glScissor(0, 0, viewWidth, height);
298 }
Martin Radev61bd9992017-08-11 13:10:55 +0300299 glClearColor(0, 0, 0, 1);
Martin Radev8f276e22017-05-30 12:05:52 +0300300 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Martin Radev3c25ad02017-08-22 17:36:53 +0300301 }
Martin Radev8f276e22017-05-30 12:05:52 +0300302
Martin Radev72b4e1e2017-08-31 15:42:56 +0300303 void createFBO(int viewWidth, int height, int numViews)
304 {
305 createFBO(viewWidth, height, numViews, numViews, 0);
306 }
307
Martin Radev3c25ad02017-08-22 17:36:53 +0300308 GLColor GetViewColor(int x, int y, int view)
309 {
310 switch (mMultiviewLayout)
311 {
312 case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
313 return ReadColor(view * mViewWidth + x, y);
314 case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
315 ASSERT(static_cast<size_t>(view) < mReadFramebuffer.size());
316 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
317 return ReadColor(x, y);
318 default:
319 UNREACHABLE();
320 }
321 return GLColor(0, 0, 0, 0);
Martin Radev8f276e22017-05-30 12:05:52 +0300322 }
323
324 GLTexture mColorTexture;
325 GLTexture mDepthTexture;
326 GLFramebuffer mDrawFramebuffer;
Martin Radev3c25ad02017-08-22 17:36:53 +0300327 std::vector<GLFramebuffer> mReadFramebuffer;
328 GLenum mMultiviewLayout;
329 int mViewWidth;
330 int mViewHeight;
331 int mNumViews;
Martin Radev8f276e22017-05-30 12:05:52 +0300332};
333
Martin Radev3c25ad02017-08-22 17:36:53 +0300334class MultiviewRenderTest : public MultiviewRenderTestBase,
335 public ::testing::TestWithParam<MultiviewTestParams>
Martin Radev8f276e22017-05-30 12:05:52 +0300336{
337 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300338 MultiviewRenderTest() : MultiviewRenderTestBase(GetParam(), GetParam().mMultiviewLayout) {}
339 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
340};
341
342class MultiviewRenderDualViewTest : public MultiviewRenderTest
343{
344 protected:
345 MultiviewRenderDualViewTest() : mProgram(0u) {}
346 ~MultiviewRenderDualViewTest()
Martin Radev8f276e22017-05-30 12:05:52 +0300347 {
348 if (mProgram != 0u)
349 {
350 glDeleteProgram(mProgram);
351 }
352 }
353
354 void SetUp() override
355 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300356 MultiviewRenderTest::SetUp();
Martin Radev8f276e22017-05-30 12:05:52 +0300357
358 if (!requestMultiviewExtension())
359 {
360 return;
361 }
362
363 const std::string vsSource =
364 "#version 300 es\n"
365 "#extension GL_OVR_multiview : require\n"
366 "layout(num_views = 2) in;\n"
367 "in vec4 vPosition;\n"
368 "void main()\n"
369 "{\n"
370 " gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x*0.5 + 0.5 : vPosition.x*0.5);\n"
371 " gl_Position.yzw = vPosition.yzw;\n"
372 "}\n";
373
374 const std::string fsSource =
375 "#version 300 es\n"
376 "#extension GL_OVR_multiview : require\n"
377 "precision mediump float;\n"
378 "out vec4 col;\n"
379 "void main()\n"
380 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300381 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300382 "}\n";
383
Martin Radev3c25ad02017-08-22 17:36:53 +0300384 createFBO(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +0300385 mProgram = CompileProgram(vsSource, fsSource);
386 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300387 glUseProgram(mProgram);
388 ASSERT_GL_NO_ERROR();
389 }
390
391 void checkOutput()
392 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300393 EXPECT_EQ(GLColor::black, GetViewColor(0, 0, 0));
394 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
395 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
396 EXPECT_EQ(GLColor::black, GetViewColor(1, 0, 1));
Martin Radev8f276e22017-05-30 12:05:52 +0300397 }
398
399 GLuint mProgram;
400};
401
Martin Radev3c25ad02017-08-22 17:36:53 +0300402class MultiviewOcclusionQueryTest : public MultiviewRenderTest
Martin Radev0d671c92017-08-10 16:41:52 +0300403{
404 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300405 MultiviewOcclusionQueryTest() {}
Martin Radev0d671c92017-08-10 16:41:52 +0300406
407 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
408 {
409 GLuint query;
410 glGenQueries(1, &query);
411 glBeginQuery(GL_ANY_SAMPLES_PASSED, query);
412 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
413 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
414
415 GLuint result = GL_TRUE;
416 glGetQueryObjectuiv(query, GL_QUERY_RESULT, &result);
417 return result;
418 }
419};
420
Martin Radev3c25ad02017-08-22 17:36:53 +0300421class MultiviewProgramGenerationTest : public MultiviewRenderTest
Martin Radev41ac68e2017-06-06 12:16:58 +0300422{
423 protected:
424 MultiviewProgramGenerationTest() {}
425};
426
Martin Radev3c25ad02017-08-22 17:36:53 +0300427class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
Martin Radev61bd9992017-08-11 13:10:55 +0300428{
429 protected:
Martin Radev3c25ad02017-08-22 17:36:53 +0300430 MultiviewRenderPrimitiveTest() {}
Martin Radev61bd9992017-08-11 13:10:55 +0300431
432 void setupGeometry(const std::vector<Vector2> &vertexData)
433 {
Martin Radev61bd9992017-08-11 13:10:55 +0300434 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
435 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
436 GL_STATIC_DRAW);
437 glEnableVertexAttribArray(0);
438 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
439 }
440
Martin Radev3c25ad02017-08-22 17:36:53 +0300441 void checkRedChannel(const GLubyte expectedRedChannelData[])
Martin Radev61bd9992017-08-11 13:10:55 +0300442 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300443 for (int view = 0; view < mNumViews; ++view)
Martin Radev61bd9992017-08-11 13:10:55 +0300444 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300445 for (int w = 0; w < mViewWidth; ++w)
Martin Radev61bd9992017-08-11 13:10:55 +0300446 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300447 for (int h = 0; h < mViewHeight; ++h)
448 {
449 size_t flatIndex =
450 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
451 EXPECT_EQ(GLColor(expectedRedChannelData[flatIndex], 0, 0, 255),
452 GetViewColor(w, h, view));
453 }
Martin Radev61bd9992017-08-11 13:10:55 +0300454 }
455 }
456 }
Martin Radev61bd9992017-08-11 13:10:55 +0300457 GLBuffer mVBO;
458};
459
Martin Radev3c25ad02017-08-22 17:36:53 +0300460class MultiviewSideBySideRenderTest : public MultiviewRenderTestBase,
461 public ::testing::TestWithParam<PlatformParameters>
462{
463 protected:
464 MultiviewSideBySideRenderTest()
465 : MultiviewRenderTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
466 {
467 }
468 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
469};
470
Martin Radev72b4e1e2017-08-31 15:42:56 +0300471class MultiviewLayeredRenderTest : public MultiviewRenderTestBase,
472 public ::testing::TestWithParam<PlatformParameters>
473{
474 protected:
475 MultiviewLayeredRenderTest()
476 : MultiviewRenderTestBase(GetParam(), GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE)
477 {
478 }
479 void SetUp() override { MultiviewRenderTestBase::RenderTestSetUp(); }
480};
481
Martin Radev14a26ae2017-07-24 15:56:29 +0300482// The test verifies that glDraw*Indirect:
483// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
484// than 1.
485// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +0300486TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300487{
488 if (!requestMultiviewExtension())
489 {
490 return;
491 }
492
Martin Radev14a26ae2017-07-24 15:56:29 +0300493 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +0300494
495 const std::string fsSource =
496 "#version 300 es\n"
497 "#extension GL_OVR_multiview : require\n"
498 "precision mediump float;\n"
499 "void main()\n"
500 "{}\n";
501
Martin Radev14a26ae2017-07-24 15:56:29 +0300502 GLBuffer commandBuffer;
503 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
504 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
505 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
506 ASSERT_GL_NO_ERROR();
507
Martin Radev14a26ae2017-07-24 15:56:29 +0300508 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
509 {
510 const std::string &vsSource =
511 "#version 300 es\n"
512 "#extension GL_OVR_multiview : require\n"
513 "layout(num_views = 2) in;\n"
514 "void main()\n"
515 "{}\n";
516 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
517 glUseProgram(program);
518
Martin Radev7cf61662017-07-26 17:10:53 +0300519 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
520 0, 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300521
522 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
523 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
524
525 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
526 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
527 }
528
529 // Check that no errors are generated if the number of views is 1.
530 {
531 const std::string &vsSource =
532 "#version 300 es\n"
533 "#extension GL_OVR_multiview : require\n"
534 "layout(num_views = 1) in;\n"
535 "void main()\n"
536 "{}\n";
537 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
538 glUseProgram(program);
539
Martin Radev7cf61662017-07-26 17:10:53 +0300540 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
541 0, 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300542
543 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
544 EXPECT_GL_NO_ERROR();
545
546 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
547 EXPECT_GL_NO_ERROR();
548 }
549}
550
Martin Radev7cf61662017-07-26 17:10:53 +0300551// The test verifies that glDraw*:
552// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
553// program differs.
554// 2) does not generate any error if the number of views is the same.
555// 3) does not generate any error if the program does not use the multiview extension.
556TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
557{
558 if (!requestMultiviewExtension())
559 {
560 return;
561 }
562
563 const GLint viewportOffsets[4] = {0, 0, 2, 0};
564
565 const std::string &vsSource =
566 "#version 300 es\n"
567 "#extension GL_OVR_multiview : require\n"
568 "layout(num_views = 2) in;\n"
569 "void main()\n"
570 "{}\n";
571 const std::string &fsSource =
572 "#version 300 es\n"
573 "#extension GL_OVR_multiview : require\n"
574 "precision mediump float;\n"
575 "void main()\n"
576 "{}\n";
577 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
578 glUseProgram(program);
579
580 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
581 // number of views.
582 {
583 // The framebuffer has only 1 view.
584 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
585 0, 1, &viewportOffsets[0]);
586
587 glDrawArrays(GL_TRIANGLES, 0, 3);
588 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
589
590 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
591 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
592 }
593
594 // Check that no errors are generated if the number of views in both program and draw
595 // framebuffer matches.
596 {
597 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
598 0, 2, &viewportOffsets[0]);
599
600 glDrawArrays(GL_TRIANGLES, 0, 3);
601 EXPECT_GL_NO_ERROR();
602
603 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
604 EXPECT_GL_NO_ERROR();
605 }
606
607 // Check that no errors are generated if the program does not use the multiview extension.
608 {
609 const std::string &vsSourceNoMultiview =
610 "#version 300 es\n"
611 "void main()\n"
612 "{}\n";
613 const std::string &fsSourceNoMultiview =
614 "#version 300 es\n"
615 "precision mediump float;\n"
616 "void main()\n"
617 "{}\n";
618 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
619 glUseProgram(programNoMultiview);
620
621 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
622 0, 2, &viewportOffsets[0]);
623
624 glDrawArrays(GL_TRIANGLES, 0, 3);
625 EXPECT_GL_NO_ERROR();
626
627 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
628 EXPECT_GL_NO_ERROR();
629 }
630}
631
Martin Radev7e69f762017-07-27 14:54:13 +0300632// The test verifies that glDraw*:
633// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
634// greater than 1 and there is an active transform feedback object.
635// 2) does not generate any error if the number of views in the draw framebuffer is 1.
636TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
637{
638 if (!requestMultiviewExtension())
639 {
640 return;
641 }
642
643 const GLint viewportOffsets[4] = {0, 0, 2, 0};
644
645 const std::string &vsSource =
646 "#version 300 es\n"
647 "void main()\n"
648 "{}\n";
649 const std::string &fsSource =
650 "#version 300 es\n"
651 "precision mediump float;\n"
652 "void main()\n"
653 "{}\n";
654 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
655 glUseProgram(program);
656
657 GLBuffer tbo;
658 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
659 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4u, nullptr, GL_STATIC_DRAW);
660
661 GLTransformFeedback transformFeedback;
662 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
663 glBeginTransformFeedback(GL_TRIANGLES);
664 ASSERT_GL_NO_ERROR();
665
666 // Check that drawArrays generates an error when there is an active transform feedback object
667 // and the number of views in the draw framebuffer is greater than 1.
668 {
669 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
670 0, 2, &viewportOffsets[0]);
671 glDrawArrays(GL_TRIANGLES, 0, 3);
672 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
673 }
674
675 // Check that drawArrays does not generate an error when the number of views in the draw
676 // framebuffer is 1.
677 {
678 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
679 0, 1, &viewportOffsets[0]);
680 glDrawArrays(GL_TRIANGLES, 0, 3);
681 EXPECT_GL_NO_ERROR();
682 }
683
684 glEndTransformFeedback();
685}
686
Martin Radevffe754b2017-07-31 10:38:07 +0300687// The test verifies that glDraw*:
688// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
689// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
690// 2) does not generate any error if the number of views in the draw framebuffer is 1.
691TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
692{
693 if (!requestMultiviewExtension())
694 {
695 return;
696 }
697
698 if (!extensionEnabled("GL_EXT_disjoint_timer_query"))
699 {
700 std::cout << "Test skipped because GL_EXT_disjoint_timer_query is not available."
701 << std::endl;
702 return;
703 }
704
705 const GLint viewportOffsets[4] = {0, 0, 2, 0};
706 const std::string &vsSource =
707 "#version 300 es\n"
708 "void main()\n"
709 "{}\n";
710 const std::string &fsSource =
711 "#version 300 es\n"
712 "precision mediump float;\n"
713 "void main()\n"
714 "{}\n";
715 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
716 glUseProgram(program);
717
718 GLuint query = 0u;
719 glGenQueriesEXT(1, &query);
720 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
721
722 // Check first case.
723 {
724 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
725 0, 2, &viewportOffsets[0]);
726 glDrawArrays(GL_TRIANGLES, 0, 3);
727 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
728 }
729
730 // Check second case.
731 {
732 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
733 0, 1, &viewportOffsets[0]);
734 glDrawArrays(GL_TRIANGLES, 0, 3);
735 EXPECT_GL_NO_ERROR();
736 }
737
738 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
739 glDeleteQueries(1, &query);
740}
741
Martin Radev8f276e22017-05-30 12:05:52 +0300742// The test checks that glDrawArrays can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300743TEST_P(MultiviewRenderDualViewTest, DrawArrays)
Martin Radev8f276e22017-05-30 12:05:52 +0300744{
745 if (!requestMultiviewExtension())
746 {
747 return;
748 }
749 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
750 ASSERT_GL_NO_ERROR();
751
752 checkOutput();
753}
754
755// The test checks that glDrawElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300756TEST_P(MultiviewRenderDualViewTest, DrawElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300757{
758 if (!requestMultiviewExtension())
759 {
760 return;
761 }
762 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
763 ASSERT_GL_NO_ERROR();
764
765 checkOutput();
766}
767
768// The test checks that glDrawRangeElements can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300769TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
Martin Radev8f276e22017-05-30 12:05:52 +0300770{
771 if (!requestMultiviewExtension())
772 {
773 return;
774 }
775 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
776 ASSERT_GL_NO_ERROR();
777
778 checkOutput();
779}
780
781// The test checks that glDrawArrays can be used to render into four views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300782TEST_P(MultiviewRenderTest, DrawArraysFourViews)
Martin Radev8f276e22017-05-30 12:05:52 +0300783{
784 if (!requestMultiviewExtension())
785 {
786 return;
787 }
788
789 const std::string vsSource =
790 "#version 300 es\n"
791 "#extension GL_OVR_multiview2 : require\n"
792 "layout(num_views = 4) in;\n"
793 "in vec4 vPosition;\n"
794 "void main()\n"
795 "{\n"
796 " if (gl_ViewID_OVR == 0u) {\n"
797 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
798 " } else if (gl_ViewID_OVR == 1u) {\n"
799 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
800 " } else if (gl_ViewID_OVR == 2u) {\n"
801 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
802 " } else {\n"
803 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
804 " }"
805 " gl_Position.yzw = vPosition.yzw;\n"
806 "}\n";
807
808 const std::string fsSource =
809 "#version 300 es\n"
810 "#extension GL_OVR_multiview2 : require\n"
811 "precision mediump float;\n"
812 "out vec4 col;\n"
813 "void main()\n"
814 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300815 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300816 "}\n";
817
Martin Radev3c25ad02017-08-22 17:36:53 +0300818 createFBO(4, 1, 4);
Martin Radev8f276e22017-05-30 12:05:52 +0300819 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
820 glUseProgram(program);
821
822 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
823 ASSERT_GL_NO_ERROR();
824
825 for (int i = 0; i < 4; ++i)
826 {
827 for (int j = 0; j < 4; ++j)
828 {
Martin Radev8f276e22017-05-30 12:05:52 +0300829 if (i == j)
830 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300831 EXPECT_EQ(GLColor::red, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300832 }
833 else
834 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300835 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, i));
Martin Radev8f276e22017-05-30 12:05:52 +0300836 }
837 }
838 }
839 EXPECT_GL_NO_ERROR();
840}
841
842// The test checks that glDrawArraysInstanced can be used to render into two views.
Martin Radev3c25ad02017-08-22 17:36:53 +0300843TEST_P(MultiviewRenderTest, DrawArraysInstanced)
Martin Radev8f276e22017-05-30 12:05:52 +0300844{
845 if (!requestMultiviewExtension())
846 {
847 return;
848 }
849
850 const std::string vsSource =
851 "#version 300 es\n"
852 "#extension GL_OVR_multiview : require\n"
853 "layout(num_views = 2) in;\n"
854 "in vec4 vPosition;\n"
855 "void main()\n"
856 "{\n"
857 " vec4 p = vPosition;\n"
858 " if (gl_InstanceID == 1){\n"
859 " p.y = .5*p.y + .5;\n"
860 " } else {\n"
861 " p.y = p.y*.5;\n"
862 " }\n"
863 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x*0.5 + 0.5 : p.x*0.5);\n"
864 " gl_Position.yzw = p.yzw;\n"
865 "}\n";
866
867 const std::string fsSource =
868 "#version 300 es\n"
869 "#extension GL_OVR_multiview : require\n"
870 "precision mediump float;\n"
871 "out vec4 col;\n"
872 "void main()\n"
873 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300874 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300875 "}\n";
876
Martin Radev3c25ad02017-08-22 17:36:53 +0300877 const int kViewWidth = 2;
878 const int kViewHeight = 2;
879 const int kNumViews = 2;
880 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev8f276e22017-05-30 12:05:52 +0300881 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
882 glUseProgram(program);
883
884 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 2);
885 ASSERT_GL_NO_ERROR();
886
Martin Radev3c25ad02017-08-22 17:36:53 +0300887 const GLubyte expectedRedChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
888 {{255, 0}, {255, 0}}};
889
890 for (int view = 0; view < 2; ++view)
Martin Radev8f276e22017-05-30 12:05:52 +0300891 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300892 for (int y = 0; y < 2; ++y)
Martin Radev8f276e22017-05-30 12:05:52 +0300893 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300894 for (int x = 0; x < 2; ++x)
895 {
896 EXPECT_EQ(GLColor(expectedRedChannel[view][y][x], 0, 0, 255),
897 GetViewColor(x, y, view));
898 }
Martin Radev8f276e22017-05-30 12:05:52 +0300899 }
900 }
901}
902
Martin Radev553590a2017-07-31 16:40:39 +0300903// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
904// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
905// offset of each quad are passed as separate attributes which are indexed based on the
906// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
907// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
908// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
909// not by 3.
Martin Radev3c25ad02017-08-22 17:36:53 +0300910TEST_P(MultiviewRenderTest, AttribDivisor)
Martin Radev553590a2017-07-31 16:40:39 +0300911{
912 if (!requestMultiviewExtension())
913 {
914 return;
915 }
916
917 const std::string &vsSource =
918 "#version 300 es\n"
919 "#extension GL_OVR_multiview2 : require\n"
920 "layout(num_views = 2) in;\n"
921 "in vec3 vPosition;\n"
922 "in float offsetX;\n"
923 "in float offsetY;\n"
924 "void main()\n"
925 "{\n"
926 " vec4 p = vec4(vPosition, 1.);\n"
Martin Radev0abb7a22017-08-28 15:34:45 +0300927 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300928 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
929 " gl_Position.yzw = p.yzw;\n"
930 "}\n";
931
932 const std::string &fsSource =
933 "#version 300 es\n"
934 "#extension GL_OVR_multiview2 : require\n"
935 "precision mediump float;\n"
936 "out vec4 col;\n"
937 "void main()\n"
938 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300939 " col = vec4(1,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300940 "}\n";
Martin Radev3c25ad02017-08-22 17:36:53 +0300941
942 const int kViewWidth = 4;
943 const int kViewHeight = 4;
944 const int kNumViews = 2;
945 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev553590a2017-07-31 16:40:39 +0300946 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
947 glUseProgram(program);
948
949 GLBuffer xOffsetVBO;
950 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
951 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
952 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
953 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
954 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
955 glVertexAttribDivisor(xOffsetLoc, 3);
956 glEnableVertexAttribArray(xOffsetLoc);
957
958 GLBuffer yOffsetVBO;
959 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
960 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
961 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
962 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
963 glVertexAttribDivisor(yOffsetLoc, 1);
964 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
965 glEnableVertexAttribArray(yOffsetLoc);
966
967 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
968 ASSERT_GL_NO_ERROR();
969
Martin Radev3c25ad02017-08-22 17:36:53 +0300970 const GLubyte expectedRedChannel[kNumViews][kViewHeight][kViewWidth] = {
971 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
972 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
973 for (int view = 0; view < 2; ++view)
Martin Radev553590a2017-07-31 16:40:39 +0300974 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300975 for (int row = 0; row < 4; ++row)
Martin Radev553590a2017-07-31 16:40:39 +0300976 {
Martin Radev3c25ad02017-08-22 17:36:53 +0300977 for (int col = 0; col < 4; ++col)
978 {
979 EXPECT_EQ(GLColor(expectedRedChannel[view][row][col], 0, 0, 255),
980 GetViewColor(col, row, view));
981 }
Martin Radev553590a2017-07-31 16:40:39 +0300982 }
983 }
984}
985
986// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
987// multi-view context propagate the correct divisor to the driver.
Martin Radev3c25ad02017-08-22 17:36:53 +0300988TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
Martin Radev553590a2017-07-31 16:40:39 +0300989{
990 if (!requestMultiviewExtension())
991 {
992 return;
993 }
994
Martin Radev3c25ad02017-08-22 17:36:53 +0300995 createFBO(1, 1, 2);
Martin Radev553590a2017-07-31 16:40:39 +0300996
997 // Create multiview program.
998 const std::string &vs =
999 "#version 300 es\n"
1000 "#extension GL_OVR_multiview2 : require\n"
1001 "layout(num_views = 2) in;\n"
1002 "layout(location = 0) in vec2 vPosition;\n"
1003 "layout(location = 1) in float offsetX;\n"
1004 "void main()\n"
1005 "{\n"
1006 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1007 " p.x += offsetX;\n"
1008 " gl_Position = p;\n"
1009 "}\n";
1010
1011 const std::string &fs =
1012 "#version 300 es\n"
1013 "#extension GL_OVR_multiview2 : require\n"
1014 "precision mediump float;\n"
1015 "out vec4 col;\n"
1016 "void main()\n"
1017 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001018 " col = vec4(1,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001019 "}\n";
1020
1021 ANGLE_GL_PROGRAM(program, vs, fs);
1022
1023 const std::string &dummyVS =
1024 "#version 300 es\n"
1025 "layout(location = 0) in vec2 vPosition;\n"
1026 "layout(location = 1) in float offsetX;\n"
1027 "void main()\n"
1028 "{\n"
1029 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1030 "}\n";
1031
1032 const std::string &dummyFS =
1033 "#version 300 es\n"
1034 "precision mediump float;\n"
1035 "out vec4 col;\n"
1036 "void main()\n"
1037 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +03001038 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +03001039 "}\n";
1040
1041 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
1042
1043 GLBuffer xOffsetVBO;
1044 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1045 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1046 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1047 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1048
1049 GLBuffer vertexVBO;
1050 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1051 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1052 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1053 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1054
1055 GLVertexArray vao[2];
1056 for (size_t i = 0u; i < 2u; ++i)
1057 {
1058 glBindVertexArray(vao[i]);
1059
1060 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1061 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1062 glEnableVertexAttribArray(0);
1063
1064 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1065 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1066 glEnableVertexAttribArray(1);
1067 }
1068 ASSERT_GL_NO_ERROR();
1069
1070 glViewport(0, 0, 1, 1);
1071 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +03001072 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +03001073 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +03001074
1075 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1076 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1077 // bits are cleared.
1078 glUseProgram(dummyProgram);
1079 glBindVertexArray(vao[0]);
1080 glVertexAttribDivisor(1, 0);
1081 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1082 glUseProgram(0);
1083 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1084 ASSERT_GL_NO_ERROR();
1085
1086 // Check that vertexAttribDivisor uses the number of views to update the divisor.
1087 glUseProgram(program);
1088 glVertexAttribDivisor(1, 1);
1089 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001090 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1091 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001092
1093 // Clear the buffers and propagate divisor to the driver.
1094 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1095 // dirty bits when useProgram is called.
1096 glUseProgram(dummyProgram);
1097 glVertexAttribDivisor(1, 1);
1098 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1099 glUseProgram(0);
1100 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1101 ASSERT_GL_NO_ERROR();
1102
1103 // Check that useProgram uses the number of views to update the divisor.
1104 glUseProgram(program);
1105 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001106 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1107 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
Martin Radev553590a2017-07-31 16:40:39 +03001108
1109 // We go through similar steps as before.
1110 glUseProgram(dummyProgram);
1111 glVertexAttribDivisor(1, 1);
1112 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1113 glUseProgram(0);
1114 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1115 ASSERT_GL_NO_ERROR();
1116
1117 // Check that bindVertexArray uses the number of views to update the divisor.
1118 {
1119 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1120 // divisor for vao[1] only.
1121 glBindVertexArray(vao[1]);
1122 glUseProgram(program);
1123 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1124 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1125 glBindVertexArray(0);
1126 ASSERT_GL_NO_ERROR();
1127 }
1128 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1129 // adjusts the divisor.
1130 glBindVertexArray(vao[0]);
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
Martin Radev0d671c92017-08-10 16:41:52 +03001136// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1137// transforms geometry to be outside of the clip region.
Martin Radev3c25ad02017-08-22 17:36:53 +03001138TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001139{
1140 if (!requestMultiviewExtension())
1141 {
1142 return;
1143 }
1144
1145 const std::string vsSource =
1146 "#version 300 es\n"
1147 "#extension GL_OVR_multiview : require\n"
1148 "layout(num_views = 2) in;\n"
1149 "in vec3 vPosition;\n"
1150 "void main()\n"
1151 "{\n"
1152 " gl_Position.x = 2.0;\n"
1153 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1154 "}\n";
1155
1156 const std::string fsSource =
1157 "#version 300 es\n"
1158 "#extension GL_OVR_multiview : require\n"
1159 "precision mediump float;\n"
1160 "out vec4 col;\n"
1161 "void main()\n"
1162 "{\n"
1163 " col = vec4(1,0,0,0);\n"
1164 "}\n";
1165 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1166 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001167 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001168
1169 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1170 ASSERT_GL_NO_ERROR();
1171 EXPECT_GL_FALSE(result);
1172}
1173
1174// Test that there are fragments passing the occlusion query if only view 0 can produce
1175// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001176TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001177{
1178 if (!requestMultiviewExtension())
1179 {
1180 return;
1181 }
1182
1183 const std::string vsSource =
1184 "#version 300 es\n"
1185 "#extension GL_OVR_multiview : require\n"
1186 "layout(num_views = 2) in;\n"
1187 "in vec3 vPosition;\n"
1188 "void main()\n"
1189 "{\n"
1190 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1191 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1192 "}\n";
1193
1194 const std::string fsSource =
1195 "#version 300 es\n"
1196 "#extension GL_OVR_multiview : require\n"
1197 "precision mediump float;\n"
1198 "out vec4 col;\n"
1199 "void main()\n"
1200 "{\n"
1201 " col = vec4(1,0,0,0);\n"
1202 "}\n";
1203 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1204 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001205 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001206
1207 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1208 ASSERT_GL_NO_ERROR();
1209 EXPECT_GL_TRUE(result);
1210}
1211
1212// Test that there are fragments passing the occlusion query if only view 1 can produce
1213// output.
Martin Radev3c25ad02017-08-22 17:36:53 +03001214TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
Martin Radev0d671c92017-08-10 16:41:52 +03001215{
1216 if (!requestMultiviewExtension())
1217 {
1218 return;
1219 }
1220
1221 const std::string vsSource =
1222 "#version 300 es\n"
1223 "#extension GL_OVR_multiview : require\n"
1224 "layout(num_views = 2) in;\n"
1225 "in vec3 vPosition;\n"
1226 "void main()\n"
1227 "{\n"
1228 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1229 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1230 "}\n";
1231
1232 const std::string fsSource =
1233 "#version 300 es\n"
1234 "#extension GL_OVR_multiview : require\n"
1235 "precision mediump float;\n"
1236 "out vec4 col;\n"
1237 "void main()\n"
1238 "{\n"
1239 " col = vec4(1,0,0,0);\n"
1240 "}\n";
1241 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1242 glUseProgram(program);
Martin Radev3c25ad02017-08-22 17:36:53 +03001243 createFBO(1, 1, 2);
Martin Radev0d671c92017-08-10 16:41:52 +03001244
1245 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1246 ASSERT_GL_NO_ERROR();
1247 EXPECT_GL_TRUE(result);
1248}
1249
Martin Radev41ac68e2017-06-06 12:16:58 +03001250// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1251// compiles and links without an error.
1252TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1253{
1254 if (!requestMultiviewExtension())
1255 {
1256 return;
1257 }
1258
1259 const std::string vsSource =
1260 "#version 300 es\n"
1261 "#extension GL_OVR_multiview : require\n"
1262 "layout(num_views = 2) in;\n"
1263 "void main()\n"
1264 "{\n"
1265 "}\n";
1266
1267 const std::string fsSource =
1268 "#version 300 es\n"
1269 "#extension GL_OVR_multiview : require\n"
1270 "precision mediump float;\n"
1271 "void main()\n"
1272 "{\n"
1273 "}\n";
1274
1275 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1276 glUseProgram(program);
1277
1278 EXPECT_GL_NO_ERROR();
1279}
1280
1281// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1282// without an error.
1283TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1284{
1285 if (!requestMultiviewExtension())
1286 {
1287 return;
1288 }
1289
1290 const std::string vsSource =
1291 "#version 300 es\n"
1292 "#extension GL_OVR_multiview2 : require\n"
1293 "layout(num_views = 2) in;\n"
1294 "void main()\n"
1295 "{\n"
1296 " if (gl_ViewID_OVR == 0u) {\n"
1297 " gl_Position = vec4(1,0,0,1);\n"
1298 " } else {\n"
1299 " gl_Position = vec4(-1,0,0,1);\n"
1300 " }\n"
1301 "}\n";
1302
1303 const std::string fsSource =
1304 "#version 300 es\n"
1305 "#extension GL_OVR_multiview2 : require\n"
1306 "precision mediump float;\n"
1307 "void main()\n"
1308 "{\n"
1309 "}\n";
1310
1311 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1312 glUseProgram(program);
1313
1314 EXPECT_GL_NO_ERROR();
1315}
1316
1317// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1318// without an error.
1319TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1320{
1321 if (!requestMultiviewExtension())
1322 {
1323 return;
1324 }
1325
1326 const std::string vsSource =
1327 "#version 300 es\n"
1328 "#extension GL_OVR_multiview2 : require\n"
1329 "layout(num_views = 2) in;\n"
1330 "void main()\n"
1331 "{\n"
1332 "}\n";
1333
1334 const std::string fsSource =
1335 "#version 300 es\n"
1336 "#extension GL_OVR_multiview2 : require\n"
1337 "precision mediump float;\n"
1338 "out vec4 col;\n"
1339 "void main()\n"
1340 "{\n"
1341 " if (gl_ViewID_OVR == 0u) {\n"
1342 " col = vec4(1,0,0,1);\n"
1343 " } else {\n"
1344 " col = vec4(-1,0,0,1);\n"
1345 " }\n"
1346 "}\n";
1347
1348 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1349 glUseProgram(program);
1350
1351 EXPECT_GL_NO_ERROR();
1352}
1353
Martin Radev61bd9992017-08-11 13:10:55 +03001354// The test checks that GL_POINTS is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001355TEST_P(MultiviewRenderPrimitiveTest, Points)
Martin Radev61bd9992017-08-11 13:10:55 +03001356{
1357 if (!requestMultiviewExtension())
1358 {
1359 return;
1360 }
1361
1362 const std::string vsSource =
1363 "#version 300 es\n"
1364 "#extension GL_OVR_multiview : require\n"
1365 "layout(num_views = 2) in;\n"
1366 "layout(location=0) in vec2 vPosition;\n"
1367 "void main()\n"
1368 "{\n"
1369 " gl_PointSize = 1.0;\n"
1370 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1371 "}\n";
1372
1373 const std::string fsSource =
1374 "#version 300 es\n"
1375 "#extension GL_OVR_multiview : require\n"
1376 "precision mediump float;\n"
1377 "out vec4 col;\n"
1378 "void main()\n"
1379 "{\n"
1380 " col = vec4(1,0,0,1);\n"
1381 "}\n";
1382 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1383 glUseProgram(program);
1384
Martin Radev3c25ad02017-08-22 17:36:53 +03001385 const int kViewWidth = 4;
1386 const int kViewHeight = 2;
1387 const int kNumViews = 2;
1388 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001389
1390 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1391 std::vector<Vector2> vertexDataInClipSpace =
1392 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1393 setupGeometry(vertexDataInClipSpace);
1394
1395 glDrawArrays(GL_POINTS, 0, 2);
1396
Martin Radev3c25ad02017-08-22 17:36:53 +03001397 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1398 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
1399 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001400}
1401
1402// The test checks that GL_LINES is correctly rendered.
1403// The behavior of this test is not guaranteed by the spec:
1404// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1405// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1406// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1407// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001408TEST_P(MultiviewRenderPrimitiveTest, Lines)
Martin Radev61bd9992017-08-11 13:10:55 +03001409{
1410 if (!requestMultiviewExtension())
1411 {
1412 return;
1413 }
1414
Martin Radevced5c862017-08-17 16:05:29 +03001415 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001416 ASSERT_NE(program, 0u);
1417 glUseProgram(program);
1418 ASSERT_GL_NO_ERROR();
1419
Martin Radev3c25ad02017-08-22 17:36:53 +03001420 const int kViewWidth = 4;
1421 const int kViewHeight = 2;
1422 const int kNumViews = 2;
1423 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001424
1425 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1426 std::vector<Vector2> vertexDataInClipSpace =
1427 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1428 setupGeometry(vertexDataInClipSpace);
1429
1430 glDrawArrays(GL_LINES, 0, 2);
1431
Martin Radev3c25ad02017-08-22 17:36:53 +03001432 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1433 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
1434 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001435
1436 glDeleteProgram(program);
1437}
1438
1439// The test checks that GL_LINE_STRIP is correctly rendered.
1440// The behavior of this test is not guaranteed by the spec:
1441// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1442// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1443// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1444// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001445TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001446{
1447 if (!requestMultiviewExtension())
1448 {
1449 return;
1450 }
1451
Martin Radevced5c862017-08-17 16:05:29 +03001452 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001453 ASSERT_NE(program, 0u);
1454 glUseProgram(program);
1455 ASSERT_GL_NO_ERROR();
1456
Martin Radev3c25ad02017-08-22 17:36:53 +03001457 const int kViewWidth = 4;
1458 const int kViewHeight = 2;
1459 const int kNumViews = 2;
1460 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001461
1462 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1463 std::vector<Vector2> vertexDataInClipSpace =
1464 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1465 setupGeometry(vertexDataInClipSpace);
1466
1467 glDrawArrays(GL_LINE_STRIP, 0, 3);
1468
Martin Radev3c25ad02017-08-22 17:36:53 +03001469 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1470 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
1471 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001472
1473 glDeleteProgram(program);
1474}
1475
1476// The test checks that GL_LINE_LOOP is correctly rendered.
1477// The behavior of this test is not guaranteed by the spec:
1478// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1479// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1480// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1481// rule."
Martin Radev3c25ad02017-08-22 17:36:53 +03001482TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
Martin Radev61bd9992017-08-11 13:10:55 +03001483{
1484 if (!requestMultiviewExtension())
1485 {
1486 return;
1487 }
1488
Martin Radevced5c862017-08-17 16:05:29 +03001489 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001490 ASSERT_NE(program, 0u);
1491 glUseProgram(program);
1492 ASSERT_GL_NO_ERROR();
1493
Martin Radev3c25ad02017-08-22 17:36:53 +03001494 const int kViewWidth = 4;
1495 const int kViewHeight = 4;
1496 const int kNumViews = 2;
1497 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001498
1499 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1500 Vector2I(0, 3)};
1501 std::vector<Vector2> vertexDataInClipSpace =
1502 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1503 setupGeometry(vertexDataInClipSpace);
1504
1505 glDrawArrays(GL_LINE_LOOP, 0, 4);
1506
Martin Radev3c25ad02017-08-22 17:36:53 +03001507 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {
1508 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1509 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
1510 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001511
1512 glDeleteProgram(program);
1513}
1514
1515// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001516TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
Martin Radev61bd9992017-08-11 13:10:55 +03001517{
1518 if (!requestMultiviewExtension())
1519 {
1520 return;
1521 }
1522
Martin Radevced5c862017-08-17 16:05:29 +03001523 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001524 ASSERT_NE(program, 0u);
1525 glUseProgram(program);
1526 ASSERT_GL_NO_ERROR();
1527
1528 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1529 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1530 setupGeometry(vertexDataInClipSpace);
1531
Martin Radev3c25ad02017-08-22 17:36:53 +03001532 const int kViewWidth = 2;
1533 const int kViewHeight = 2;
1534 const int kNumViews = 2;
1535 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001536
1537 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1538
Martin Radev3c25ad02017-08-22 17:36:53 +03001539 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {{{0, 0}, {0, 255}},
1540 {{0, 0}, {0, 255}}};
1541 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001542
1543 glDeleteProgram(program);
1544}
1545
1546// The test checks that GL_TRIANGLE_FAN is correctly rendered.
Martin Radev3c25ad02017-08-22 17:36:53 +03001547TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
Martin Radev61bd9992017-08-11 13:10:55 +03001548{
1549 if (!requestMultiviewExtension())
1550 {
1551 return;
1552 }
1553
Martin Radevced5c862017-08-17 16:05:29 +03001554 GLuint program = CreateSimplePassthroughProgram(2);
Martin Radev61bd9992017-08-11 13:10:55 +03001555 ASSERT_NE(program, 0u);
1556 glUseProgram(program);
1557 ASSERT_GL_NO_ERROR();
1558
1559 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1560 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1561 setupGeometry(vertexDataInClipSpace);
1562
Martin Radev3c25ad02017-08-22 17:36:53 +03001563 const int kViewWidth = 2;
1564 const int kViewHeight = 2;
1565 const int kNumViews = 2;
1566 createFBO(kViewWidth, kViewHeight, kNumViews);
Martin Radev61bd9992017-08-11 13:10:55 +03001567
1568 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1569
Martin Radev3c25ad02017-08-22 17:36:53 +03001570 const GLubyte expectedRedChannelData[kNumViews][kViewHeight][kViewWidth] = {{{0, 0}, {0, 255}},
1571 {{0, 0}, {0, 255}}};
1572 checkRedChannel(expectedRedChannelData[0][0]);
Martin Radev61bd9992017-08-11 13:10:55 +03001573
1574 glDeleteProgram(program);
1575}
1576
1577// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1578// bounds. The test does not rely on the actual line width being greater than 1.0.
Martin Radev3c25ad02017-08-22 17:36:53 +03001579TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
Martin Radev61bd9992017-08-11 13:10:55 +03001580{
1581 if (!requestMultiviewExtension())
1582 {
1583 return;
1584 }
1585
Martin Radev3c25ad02017-08-22 17:36:53 +03001586 createFBO(2, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +03001587
1588 GLint viewportOffsets[4] = {1, 0, 3, 0};
1589 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1590 mColorTexture, 0, 2, &viewportOffsets[0]);
1591 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
1592 mDepthTexture, 0, 2, &viewportOffsets[0]);
1593
1594 glViewport(0, 0, 1, 1);
1595 glScissor(0, 0, 1, 1);
1596 glEnable(GL_SCISSOR_TEST);
1597
1598 const std::string vsSource =
1599 "#version 300 es\n"
1600 "#extension GL_OVR_multiview2 : require\n"
1601 "layout(num_views = 2) in;\n"
1602 "layout(location=0) in vec2 vPosition;\n"
1603 "void main()\n"
1604 "{\n"
1605 " gl_PointSize = 10.0;\n"
1606 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1607 "}\n";
1608
1609 const std::string fsSource =
1610 "#version 300 es\n"
1611 "#extension GL_OVR_multiview2 : require\n"
1612 "precision mediump float;\n"
1613 "out vec4 col;\n"
1614 "void main()\n"
1615 "{\n"
1616 " if (gl_ViewID_OVR == 0u) {\n"
1617 " col = vec4(1,0,0,1);\n"
1618 " } else {\n"
1619 " col = vec4(0,1,0,1);\n"
1620 " }\n"
1621 "}\n";
1622 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1623 glUseProgram(program);
1624
1625 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1626 const std::vector<Vector2> &vertexDataInClipSpace =
1627 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
Martin Radev3c25ad02017-08-22 17:36:53 +03001628
1629 GLBuffer vbo;
1630 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1631 glBufferData(GL_ARRAY_BUFFER, vertexDataInClipSpace.size() * sizeof(Vector2),
1632 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1633 glEnableVertexAttribArray(0);
1634 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
Martin Radev61bd9992017-08-11 13:10:55 +03001635
1636 // Test rendering points.
1637 {
1638 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1639 glDrawArrays(GL_POINTS, 0, 2);
1640 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1641 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1642 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1643 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1644 }
1645
1646 // Test rendering lines.
1647 {
1648 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1649 glLineWidth(10.f);
1650 glDrawArrays(GL_LINES, 0, 2);
1651 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1652 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1653 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1654 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1655 }
1656}
1657
Martin Radev0abb7a22017-08-28 15:34:45 +03001658// Verify that re-linking a program adjusts the attribute divisor.
1659// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1660// to each other. The quads' position and color depend on the corresponding attribute divisors.
1661TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1662{
1663 if (!requestMultiviewExtension())
1664 {
1665 return;
1666 }
1667
1668 const int kViewWidth = 4;
1669 const int kViewHeight = 1;
1670 const int kNumViews = 2;
1671
1672 const std::string &fsSource =
1673 "#version 300 es\n"
1674 "#extension GL_OVR_multiview2 : require\n"
1675 "precision mediump float;\n"
1676 "in vec4 oColor;\n"
1677 "out vec4 col;\n"
1678 "void main()\n"
1679 "{\n"
1680 " col = oColor;\n"
1681 "}\n";
1682
1683 auto generateVertexShaderSource = [](int numViews) -> std::string {
1684 std::string source =
1685 "#version 300 es\n"
1686 "#extension GL_OVR_multiview2 : require\n"
1687 "layout(num_views = " +
1688 ToString(numViews) +
1689 ") in;\n"
1690 "in vec3 vPosition;\n"
1691 "in float vOffsetX;\n"
1692 "in vec4 vColor;\n"
1693 "out vec4 oColor;\n"
1694 "void main()\n"
1695 "{\n"
1696 " vec4 p = vec4(vPosition, 1.);\n"
1697 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1698 " oColor = vColor;\n"
1699 " gl_Position = p;\n"
1700 "}\n";
1701 return source;
1702 };
1703
1704 std::string vsSource = generateVertexShaderSource(kNumViews);
1705 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1706 glUseProgram(program);
1707
1708 GLint positionLoc;
1709 GLBuffer xOffsetVBO;
1710 GLint xOffsetLoc;
1711 GLBuffer colorVBO;
1712 GLint colorLoc;
1713
1714 {
1715 // Initialize buffers and setup attributes.
1716 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1717 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1718 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1719 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1720 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1721 glVertexAttribDivisor(xOffsetLoc, 1);
1722 glEnableVertexAttribArray(xOffsetLoc);
1723
1724 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1725 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1726 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1727 colorLoc = glGetAttribLocation(program, "vColor");
1728 glVertexAttribDivisor(colorLoc, 2);
1729 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1730 glEnableVertexAttribArray(colorLoc);
1731
1732 positionLoc = glGetAttribLocation(program, "vPosition");
1733 }
1734
1735 {
1736 createFBO(kViewWidth, kViewHeight, kNumViews);
1737
1738 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
1739 ASSERT_GL_NO_ERROR();
1740
1741 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1742 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1743 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1744 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1745 }
1746
1747 {
1748 const int kNewNumViews = 3;
1749 vsSource = generateVertexShaderSource(kNewNumViews);
1750 createFBO(kViewWidth, kViewHeight, kNewNumViews);
1751
1752 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
1753 ASSERT_NE(0u, vs);
1754 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
1755 ASSERT_NE(0u, fs);
1756
1757 GLint numAttachedShaders = 0;
1758 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1759
1760 GLuint attachedShaders[2] = {0u};
1761 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1762 for (int i = 0; i < 2; ++i)
1763 {
1764 glDetachShader(program, attachedShaders[i]);
1765 }
1766
1767 glAttachShader(program, vs);
1768 glDeleteShader(vs);
1769
1770 glAttachShader(program, fs);
1771 glDeleteShader(fs);
1772
1773 glBindAttribLocation(program, positionLoc, "vPosition");
1774 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1775 glBindAttribLocation(program, colorLoc, "vColor");
1776
1777 glLinkProgram(program);
1778
1779 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
1780 ASSERT_GL_NO_ERROR();
1781
1782 for (int i = 0; i < kNewNumViews; ++i)
1783 {
1784 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1785 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1786 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1787 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1788 }
1789 }
1790}
1791
Martin Radevced5c862017-08-17 16:05:29 +03001792// Test that useProgram applies the number of views in computing the final value of the attribute
1793// divisor.
1794TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1795{
1796 if (!requestMultiviewExtension())
1797 {
1798 return;
1799 }
1800
1801 GLVertexArray vao;
1802 glBindVertexArray(vao);
1803 GLBuffer vbo;
1804 glBindBuffer(GL_ARRAY_BUFFER, vbo);
1805 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
1806 Vector2I(3, 0)};
1807 std::vector<Vector2> vertexDataInClipSpace =
1808 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
1809 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
1810 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
1811 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
1812 glEnableVertexAttribArray(0);
1813 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
1814 glVertexAttribDivisor(0, 1);
1815 ASSERT_GL_NO_ERROR();
1816
1817 // Create a program and fbo with N views and draw N instances of a point horizontally.
1818 for (int numViews = 2; numViews <= 4; ++numViews)
1819 {
1820 createFBO(4, 1, numViews);
1821 ASSERT_GL_NO_ERROR();
1822
1823 GLuint program = CreateSimplePassthroughProgram(numViews);
1824 ASSERT_NE(program, 0u);
1825 glUseProgram(program);
1826 ASSERT_GL_NO_ERROR();
1827
1828 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
1829
1830 for (int view = 0; view < numViews; ++view)
1831 {
1832 for (int j = 0; j < numViews; ++j)
1833 {
1834 EXPECT_EQ(GLColor::red, GetViewColor(j, 0, view));
1835 }
1836 for (int j = numViews; j < 4; ++j)
1837 {
1838 EXPECT_EQ(GLColor::black, GetViewColor(j, 0, view));
1839 }
1840 }
1841
1842 glDeleteProgram(program);
1843 }
1844}
1845
Martin Radev72b4e1e2017-08-31 15:42:56 +03001846// The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
1847TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
1848{
1849 if (!requestMultiviewExtension())
1850 {
1851 return;
1852 }
1853
1854 const std::string vsSource =
1855 "#version 300 es\n"
1856 "#extension GL_OVR_multiview2 : require\n"
1857 "layout(num_views = 3) in;\n"
1858 "in vec3 vPosition;\n"
1859 "void main()\n"
1860 "{\n"
1861 " gl_Position = vec4(vPosition, 1.);\n"
1862 "}\n";
1863
1864 const std::string fsSource =
1865 "#version 300 es\n"
1866 "#extension GL_OVR_multiview2 : require\n"
1867 "precision mediump float;\n"
1868 "out vec4 col;\n"
1869 "void main()\n"
1870 "{\n"
1871 " if (gl_ViewID_OVR == 0u) {\n"
1872 " col = vec4(1,0,0,1);\n"
1873 " } else if (gl_ViewID_OVR == 1u) {\n"
1874 " col = vec4(0,1,0,1);\n"
1875 " } else if (gl_ViewID_OVR == 2u) {\n"
1876 " col = vec4(0,0,1,1);\n"
1877 " } else {\n"
1878 " col = vec4(0,0,0,0);\n"
1879 " }\n"
1880 "}\n";
1881
1882 createFBO(1, 1, 3);
1883 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1884 glUseProgram(program);
1885
1886 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1887 ASSERT_GL_NO_ERROR();
1888
1889 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1890 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1891 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
1892}
1893
1894// The test checks that the inactive layers of a 2D texture array are not written to by a
1895// multi-view program.
1896TEST_P(MultiviewLayeredRenderTest, RenderToSubrageOfLayers)
1897{
1898 if (!requestMultiviewExtension())
1899 {
1900 return;
1901 }
1902
1903 const std::string vsSource =
1904 "#version 300 es\n"
1905 "#extension GL_OVR_multiview : require\n"
1906 "layout(num_views = 2) in;\n"
1907 "in vec3 vPosition;\n"
1908 "void main()\n"
1909 "{\n"
1910 " gl_Position = vec4(vPosition, 1.);\n"
1911 "}\n";
1912
1913 const std::string fsSource =
1914 "#version 300 es\n"
1915 "#extension GL_OVR_multiview : require\n"
1916 "precision mediump float;\n"
1917 "out vec4 col;\n"
1918 "void main()\n"
1919 "{\n"
1920 " col = vec4(1,0,0,1);\n"
1921 "}\n";
1922
1923 createFBO(1, 1, 2, 4, 1);
1924 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1925 glUseProgram(program);
1926
1927 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1928 ASSERT_GL_NO_ERROR();
1929
1930 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
1931 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 1));
1932 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 2));
1933 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
1934}
1935
Martin Radev3c25ad02017-08-22 17:36:53 +03001936MultiviewTestParams SideBySideOpenGL()
1937{
1938 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, egl_platform::OPENGL());
1939}
1940
1941MultiviewTestParams LayeredOpenGL()
1942{
1943 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, egl_platform::OPENGL());
1944}
1945
1946MultiviewTestParams SideBySideD3D11()
1947{
1948 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, egl_platform::D3D11());
1949}
1950
Martin Radev72b4e1e2017-08-31 15:42:56 +03001951MultiviewTestParams LayeredD3D11()
1952{
1953 return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE, egl_platform::D3D11());
1954}
1955
Martin Radev8f276e22017-05-30 12:05:52 +03001956ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest, ES31_OPENGL());
Martin Radevced5c862017-08-17 16:05:29 +03001957ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
1958 SideBySideOpenGL(),
1959 LayeredOpenGL(),
Martin Radev72b4e1e2017-08-31 15:42:56 +03001960 SideBySideD3D11(),
1961 LayeredD3D11());
1962ANGLE_INSTANTIATE_TEST(MultiviewRenderTest,
1963 SideBySideOpenGL(),
1964 LayeredOpenGL(),
1965 SideBySideD3D11(),
1966 LayeredD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03001967ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest,
1968 SideBySideOpenGL(),
1969 LayeredOpenGL(),
Martin Radev72b4e1e2017-08-31 15:42:56 +03001970 SideBySideD3D11(),
1971 LayeredD3D11());
1972ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
1973 SideBySideOpenGL(),
1974 SideBySideD3D11(),
1975 LayeredD3D11());
Martin Radevced5c862017-08-17 16:05:29 +03001976ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest,
1977 SideBySideOpenGL(),
1978 LayeredOpenGL(),
Martin Radev72b4e1e2017-08-31 15:42:56 +03001979 SideBySideD3D11(),
1980 LayeredD3D11());
1981ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest, ES3_OPENGL(), ES3_D3D11());
1982ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, ES3_OPENGL(), ES3_D3D11());