| // |
| // Copyright 2019 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| // MultiviewMultisampledRenderToTextureTest: |
| // Tests of OVR_multiview_multisampled_render_to_texture extension |
| |
| #include <tuple> |
| #include "test_utils/ANGLETest.h" |
| #include "test_utils/gl_raii.h" |
| |
| using namespace angle; |
| |
| namespace |
| { |
| constexpr int kWindowSize = 6; |
| class MultiviewMSRTTTest : public ANGLETest<> |
| { |
| protected: |
| MultiviewMSRTTTest() |
| { |
| setWindowWidth(kWindowSize); |
| setWindowHeight(kWindowSize); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| } |
| |
| void testSetUp() override |
| { |
| if (getClientMajorVersion() >= 3) |
| { |
| glGetIntegerv(GL_MAX_SAMPLES, &mMaxIntegerSamples); |
| glGetIntegerv(GL_MAX_VIEWS_OVR, &mMaxViewsOVR); |
| glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &mMaxArrayTextureLayers); |
| } |
| } |
| |
| GLint mMaxIntegerSamples = 0; |
| GLint mMaxViewsOVR = 0; |
| GLint mMaxArrayTextureLayers = 0; |
| }; |
| |
| class MultiviewMSRTTES3Test : public MultiviewMSRTTTest |
| {}; |
| |
| // Test that INVALID_FRAMEBUFFER_OPERATION is generated by glReadPixels() command if the number |
| // of views in the current read framebuffer is greater than 1 |
| TEST_P(MultiviewMSRTTES3Test, ReadPixelsFromMultiviewFramebufferShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numLayers = 2; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| std::vector<GLubyte> textureData; |
| textureData.resize(kWindowSize * kWindowSize * numLayers * 4, 0u); |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, |
| multisampleRenderToTextureSampleSize, 0, 2); |
| ASSERT_GL_NO_ERROR(); |
| std::vector<GLColor> pixels(kWindowSize * kWindowSize * numLayers); |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); |
| EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION); |
| } |
| |
| // Test that INVALID_FRAMEBUFFER_OPERATION is generated by glCopyTexImage2D() command if the number |
| // of views in the current read framebuffer is greater than 1 |
| TEST_P(MultiviewMSRTTES3Test, CopyTexImageFromMultiviewFramebufferShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numLayers = 2; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| std::vector<GLubyte> textureData; |
| textureData.resize(kWindowSize * kWindowSize * numLayers * 4, 0u); |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, |
| multisampleRenderToTextureSampleSize, 0, 2); |
| ASSERT_GL_NO_ERROR(); |
| GLTexture copyImageTargetTexture; |
| glBindTexture(GL_TEXTURE_2D, copyImageTargetTexture); |
| glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, kWindowSize, kWindowSize, 0); |
| EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION); |
| } |
| |
| // Test that INVALID_FRAMEBUFFER_OPERATION is generated by glCopyTexSubImage() command if the number |
| // of views in the current read framebuffer is greater than 1 |
| TEST_P(MultiviewMSRTTES3Test, CopyTexSubImageFromMultiviewFramebufferShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numLayers = 2; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| std::vector<GLubyte> textureData; |
| textureData.resize(kWindowSize * kWindowSize * numLayers * 4, 0u); |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, |
| multisampleRenderToTextureSampleSize, 0, 2); |
| ASSERT_GL_NO_ERROR(); |
| GLTexture copySubImageTargetTexture; |
| glBindTexture(GL_TEXTURE_2D, copySubImageTargetTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWindowSize, kWindowSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| nullptr); |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kWindowSize, kWindowSize); |
| EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION); |
| } |
| |
| // Test that INVALID_FRAMEBUFFER_OPERATION is generated by glCopyTexSubImage3D() command if the |
| // number of views in the current read framebuffer is greater than 1 |
| TEST_P(MultiviewMSRTTES3Test, CopyTexSubImage3DFromMultiviewFramebufferShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numLayers = 2; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| std::vector<GLubyte> textureData; |
| textureData.resize(kWindowSize * kWindowSize * numLayers * 4, 0u); |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, |
| multisampleRenderToTextureSampleSize, 0, 2); |
| ASSERT_GL_NO_ERROR(); |
| GLTexture copySubImage3DTargetTexture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, copySubImage3DTargetTexture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glCopyTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 0, 0, kWindowSize, kWindowSize); |
| EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION); |
| } |
| |
| // Test that INVALID_VALUE is generated by FramebufferTextureMultisampleMultiviewOVR if numViews is |
| // less than 1 |
| TEST_P(MultiviewMSRTTES3Test, NumViewsLessThanOneShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numLayers = 2; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| std::vector<GLubyte> textureData; |
| textureData.resize(kWindowSize * kWindowSize * numLayers * 4, 0u); |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, |
| multisampleRenderToTextureSampleSize, 0, 0); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| } |
| |
| // Test that INVALID_VALUE is generated by FramebufferTextureMultisampleMultiviewOVR if numViews is |
| // more than MAX_VIEWS_OVR |
| TEST_P(MultiviewMSRTTES3Test, NumViewsGreaterThanMaxShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numLayers = 2; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| std::vector<GLubyte> textureData; |
| textureData.resize(kWindowSize * kWindowSize * numLayers * 4, 0u); |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, |
| multisampleRenderToTextureSampleSize, 0, |
| mMaxViewsOVR + 1); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| } |
| |
| // Test that INVALID_VALUE is generated by FramebufferTextureMultisampleMultiviewOVR if |
| // (baseViewIndex + numViews) exceeds GL_MAX_ARRAY_TEXTURE_LAYERS |
| TEST_P(MultiviewMSRTTES3Test, BaseViewIndexPlusNumViewsExceedsMaxArrayTextureLayersShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numLayers = 2; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| std::vector<GLubyte> textureData; |
| textureData.resize(kWindowSize * kWindowSize * numLayers * 4, 0u); |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, |
| multisampleRenderToTextureSampleSize, |
| mMaxArrayTextureLayers, 1); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| } |
| |
| // Test that INVALID_VALUE is generated by FramebufferTextureMultisampleMultiviewOVR if samples is |
| // greater than MAX_SAMPLES |
| TEST_P(MultiviewMSRTTES3Test, SamplesGreaterThanMaxSamplesShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numLayers = 2; |
| std::vector<GLubyte> textureData; |
| textureData.resize(kWindowSize * kWindowSize * numLayers * 4, 0u); |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, |
| mMaxIntegerSamples + 1, 0, 2); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| } |
| |
| // Test that INVALID_OPERATION is generated if a rendering command is issued and the number |
| // of views in the current draw framebuffer is not equal to the number of views declared in |
| // the currently bound program. |
| TEST_P(MultiviewMSRTTES3Test, ProgramViewMismatchFramebufferViewShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| // Create a program with 2 views |
| const std::string vsSource = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| layout(num_views = 2) in; |
| in vec4 a_position; |
| void main() |
| { |
| gl_Position = a_position; |
| } |
| )"; |
| const std::string fsSource = R"(#version 300 es |
| precision mediump float; |
| out vec4 FragColor; |
| void main() |
| { |
| FragColor = vec4(1.0, 0.0, 0.0, 1.0); |
| } |
| )"; |
| |
| ANGLE_GL_PROGRAM(program, vsSource.c_str(), fsSource.c_str()); |
| glUseProgram(program); |
| |
| // Create a framebuffer with 1 view |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numLayers = 1; // 1 view in framebuffer |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| std::vector<GLubyte> textureData; |
| textureData.resize(kWindowSize * kWindowSize * numLayers * 4, 0u); |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, |
| multisampleRenderToTextureSampleSize, 0, 1); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Draw with program (2 views) and framebuffer (1 view) mismatch |
| drawQuad(program, "a_position", 0.5f, 0.5f, true); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| // Test that INVALID_OPERATION is generated if the target type of <texture> specified in |
| // FramebufferTextureMultisampleMultiviewOVR is not TEXTURE_2D_ARRAY |
| TEST_P(MultiviewMSRTTES3Test, InvalidTextureTargetShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numLayers = 2; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| std::vector<GLubyte> textureData; |
| textureData.resize(kWindowSize * kWindowSize * numLayers * 4, 0u); |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); // Bind to GL_TEXTURE_2D instead of GL_TEXTURE_2D_ARRAY |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWindowSize, kWindowSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| textureData.data()); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, |
| multisampleRenderToTextureSampleSize, 0, 2); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| // Test that calling glFramebufferTextureMultisampleMultiviewOVR() on both GL_COLOR_ATTACHMENT0 |
| // and GL_DEPTH_ATTACHMENT works, and that drawing to it works. |
| TEST_P(MultiviewMSRTTES3Test, ColorAndDepthAttachment) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| const std::string vsSource = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| layout(num_views = 2) in; |
| in vec4 a_position; |
| void main() |
| { |
| gl_Position = a_position; |
| } |
| )"; |
| const std::string fsSource = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| precision mediump float; |
| out vec4 FragColor; |
| void main() |
| { |
| if (gl_ViewID_OVR == 0u) |
| { |
| FragColor = vec4(0.0, 1.0, 0.0, 1.0); |
| gl_FragDepth = 0.25; |
| } |
| else |
| { |
| FragColor = vec4(1.0, 0.0, 0.0, 1.0); |
| gl_FragDepth = 0.75; |
| } |
| } |
| )"; |
| ANGLE_GL_PROGRAM(program, vsSource.c_str(), fsSource.c_str()); |
| glUseProgram(program); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numViews = 2; |
| constexpr int baseViewIndex = 0; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| // Color attachment |
| GLTexture colorTexture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numViews, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, |
| 0, multisampleRenderToTextureSampleSize, |
| baseViewIndex, numViews); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Depth attachment |
| GLTexture depthTexture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, depthTexture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, kWindowSize, kWindowSize, numViews, |
| 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, |
| 0, multisampleRenderToTextureSampleSize, |
| baseViewIndex, numViews); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glEnable(GL_DEPTH_TEST); |
| glClearDepthf(1.0f); |
| glClearColor(1.0f, 1.0f, 1.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| drawQuad(program, "a_position", 0.5f, 0.5f, true); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verification |
| GLFramebuffer verifyFbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, verifyFbo); |
| |
| // Verify view 0 |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, 0, |
| baseViewIndex + 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 2, GLColor::green); |
| |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, |
| baseViewIndex + 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| float depth0 = 0.0f; |
| glReadPixels(0, 0, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth0); |
| EXPECT_NEAR(1.0f, depth0, 1e-6); |
| glReadPixels(kWindowSize / 2, kWindowSize / 2, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth0); |
| EXPECT_NEAR(0.25, depth0, 1e-6); |
| |
| // Verify view 1 |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, 0, |
| baseViewIndex + 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 2, GLColor::red); |
| |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0, |
| baseViewIndex + 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| float depth1 = 0.0f; |
| glReadPixels(0, 0, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth1); |
| EXPECT_NEAR(1.0f, depth1, 1e-6); |
| glReadPixels(kWindowSize / 2, kWindowSize / 2, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth1); |
| EXPECT_NEAR(0.75, depth1, 1e-6); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that an INVALID_OPERATION error is generated if samples is greater than the maximum number |
| // of samples supported for target and its internalformat. |
| TEST_P(MultiviewMSRTTES3Test, SamplesGreaterThanMaxSamplesForTextureFormatShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| GLint maxSamplesForFormat = 0; |
| glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_RGBA8, GL_SAMPLES, 1, |
| &maxSamplesForFormat); |
| INFO() << "maxSamplesForFormat: " << maxSamplesForFormat; |
| ASSERT_GL_NO_ERROR(); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numLayers = 2; |
| std::vector<GLubyte> textureData; |
| textureData.resize(kWindowSize * kWindowSize * numLayers * 4, 0u); |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, |
| maxSamplesForFormat + 1, 0, 2); |
| |
| if (maxSamplesForFormat < mMaxIntegerSamples) |
| { |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| else |
| { |
| // GL_INVALID_VALUE error code is generated if samples > mMaxIntegerSamples |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| } |
| } |
| |
| // Test that passing samples 0 to glFramebufferTextureMultisampleMultiviewOVR() works and |
| // produces the same result as glFramebufferTextureMultiviewOVR. |
| TEST_P(MultiviewMSRTTES3Test, SamplesZeroWorks) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| const std::string vsSource = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| layout(num_views = 2) in; |
| in vec4 a_position; |
| void main() |
| { |
| gl_Position = a_position; |
| } |
| )"; |
| const std::string fsSource = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| precision mediump float; |
| out vec4 FragColor; |
| void main() |
| { |
| if (gl_ViewID_OVR == 0u) |
| { |
| FragColor = vec4(0.0, 1.0, 0.0, 1.0); |
| } |
| else |
| { |
| FragColor = vec4(1.0, 0.0, 0.0, 1.0); |
| } |
| } |
| )"; |
| ANGLE_GL_PROGRAM(program, vsSource.c_str(), fsSource.c_str()); |
| glUseProgram(program); |
| |
| constexpr int numViews = 2; |
| constexpr int baseViewIndex = 0; |
| |
| // FBO 0: Use glFramebufferTextureMultisampleMultiviewOVR with 0 samples |
| GLFramebuffer fbo0; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo0); |
| GLTexture colorTexture0; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture0); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numViews, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture0, |
| 0, 0, baseViewIndex, numViews); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| drawQuad(program, "a_position", 0.5f, 0.5f, true); |
| ASSERT_GL_NO_ERROR(); |
| |
| // FBO 1: Use glFramebufferTextureMultiviewOVR |
| GLFramebuffer fbo1; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo1); |
| GLTexture colorTexture1; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture1); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numViews, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture1, 0, |
| baseViewIndex, numViews); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| drawQuad(program, "a_position", 0.5f, 0.5f, true); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verification: Compare colorTexture0 and colorTexture1 |
| GLFramebuffer verifyFbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, verifyFbo); |
| |
| std::vector<GLColor> pixels0(kWindowSize * kWindowSize); |
| std::vector<GLColor> pixels1(kWindowSize * kWindowSize); |
| |
| for (int i = 0; i < numViews; ++i) |
| { |
| // Read from colorTexture0 |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture0, 0, |
| baseViewIndex + i); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| glReadPixels(0, 0, kWindowSize, kWindowSize, GL_RGBA, GL_UNSIGNED_BYTE, pixels0.data()); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Read from colorTexture1 |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture1, 0, |
| baseViewIndex + i); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| glReadPixels(0, 0, kWindowSize, kWindowSize, GL_RGBA, GL_UNSIGNED_BYTE, pixels1.data()); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Compare |
| EXPECT_EQ(pixels0, pixels1); |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that after calling glFramebufferTextureMultisampleMultiviewOVR, the resulting value for |
| // TEXTURE_SAMPLES_EXT is guaranteed to be greater than or equal to samples and no more than the |
| // next larger sample count supported by the implementation. |
| TEST_P(MultiviewMSRTTES3Test, FrameBufferTextureSamplesExtValue) |
| { |
| |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numViews = 2; |
| constexpr int baseViewIndex = 0; |
| constexpr GLsizei requestedSamples = 2; // Request 2 samples |
| GLTexture colorTexture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numViews, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, |
| 0, requestedSamples, baseViewIndex, numViews); |
| |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Query TEXTURE_SAMPLES_EXT from the framebuffer attachment |
| GLint actualSamples = 0; |
| glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT, |
| &actualSamples); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Get supported sample counts for GL_RGBA8 |
| GLint numSampleCounts = 0; |
| glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, 1, |
| &numSampleCounts); |
| ASSERT_GL_NO_ERROR(); |
| std::vector<GLint> supportedSampleCounts(numSampleCounts); |
| glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_SAMPLES, numSampleCounts, |
| supportedSampleCounts.data()); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Sort supported sample counts in ascending order |
| std::sort(supportedSampleCounts.begin(), supportedSampleCounts.end()); |
| // Find the smallest supported sample count that is >= requestedSamples |
| GLint expectedMaxSamples = 0; |
| if (requestedSamples == 0) |
| { |
| expectedMaxSamples = 0; |
| } |
| else |
| { |
| auto it = std::lower_bound(supportedSampleCounts.begin(), supportedSampleCounts.end(), |
| requestedSamples); |
| ASSERT(it != supportedSampleCounts.end()); |
| expectedMaxSamples = *it; |
| } |
| // Verify the conditions |
| EXPECT_GE(actualSamples, requestedSamples); |
| EXPECT_LE(actualSamples, expectedMaxSamples); |
| } |
| |
| // Test that glReadPixels() does not return an error if the GL_SAMPLE_BUFFERS of read framebuffer is |
| // 1, when the read framebuffer attachment is attached with |
| // glFramebufferTextureMultisampleMultiviewOVR() |
| TEST_P(MultiviewMSRTTES3Test, ReadPixelsFromSingleViewFramebufferShouldSucceed) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numLayers = 1; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| std::vector<GLubyte> textureData; |
| textureData.resize(kWindowSize * kWindowSize * numLayers * 4, 0u); |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, |
| multisampleRenderToTextureSampleSize, 0, 1); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); |
| GLint sampleBuffers = 0; |
| glGetIntegerv(GL_SAMPLE_BUFFERS, &sampleBuffers); |
| if (sampleBuffers == 1) |
| { |
| std::vector<GLColor> pixels(kWindowSize * kWindowSize * numLayers); |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); |
| EXPECT_GL_NO_ERROR(); |
| } |
| } |
| |
| // Test that framebuffer succeed with draw operations if the attachments are created with |
| // glFramebufferTextureMultisampleMultiviewOVR() and have the same render-to-texture sample counts |
| TEST_P(MultiviewMSRTTES3Test, FBOAttachmentsWithSameSampleCountShouldSucceed) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| constexpr GLsizei multisampleRenderToTextureSampleSize4 = 4; |
| ANGLE_SKIP_TEST_IF(mMaxIntegerSamples <= multisampleRenderToTextureSampleSize4); |
| |
| constexpr int numViews = 2; |
| constexpr int baseViewIndex = 0; |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| // Attach msrtt-multiview (4 samples) texture to COLOR_ATTACHMENT0 |
| GLTexture colorTexture0; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture0); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numViews, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture0, |
| 0, multisampleRenderToTextureSampleSize4, |
| baseViewIndex, numViews); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Attach msrtt-multiview (4 samples) texture to COLOR_ATTACHMENT1 |
| GLTexture colorTexture1; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture1); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numViews, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, colorTexture1, |
| 0, multisampleRenderToTextureSampleSize4, |
| baseViewIndex, numViews); |
| |
| const std::string vsSource = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| layout(num_views = 2) in; |
| in vec4 a_position; |
| void main() |
| { |
| gl_Position = a_position; |
| } |
| )"; |
| const std::string fsSource = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| precision mediump float; |
| layout(location = 0)out vec4 FragColor0; |
| layout(location = 1)out vec4 FragColor1; |
| void main() |
| { |
| if (gl_ViewID_OVR == 0u) { |
| FragColor0 = vec4(1.0, 0.0, 0.0, 1.0); // Red for view 0 GL_COLOR_ATTACHMENT0 |
| FragColor1 = vec4(1.0, 1.0, 0.0, 1.0); // Yellow for view 0 GL_COLOR_ATTACHMENT1 |
| } else { |
| FragColor0 = vec4(0.0, 1.0, 0.0, 1.0); // Green for view 1 GL_COLOR_ATTACHMENT0 |
| FragColor1 = vec4(0.0, 0.0, 1.0, 1.0); // Blue for view 1 GL_COLOR_ATTACHMENT1 |
| } |
| } |
| )"; |
| |
| ANGLE_GL_PROGRAM(program, vsSource.c_str(), fsSource.c_str()); |
| glUseProgram(program); |
| |
| GLenum buffers[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; |
| glDrawBuffers(2, buffers); |
| glClearColor(1.0, 1.0, 1.0, 1.0); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Draw a quad |
| drawQuad(program, "a_position", 0.5f, 0.5f, true); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify draw result |
| GLFramebuffer verifyFbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, verifyFbo); |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture0, 0, |
| baseViewIndex); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 2, GLColor::red); |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture0, 0, |
| baseViewIndex + 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 2, GLColor::green); |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture1, 0, |
| baseViewIndex); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 2, GLColor::yellow); |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture1, 0, |
| baseViewIndex + 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 2, GLColor::blue); |
| |
| // Now attach with a different render-to-texture sample count |
| // Attach msrtt-multiview (mMaxIntegerSamples samples) texture to COLOR_ATTACHMENT0 |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| GLTexture colorTexture3; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture3); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numViews, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture3, |
| 0, mMaxIntegerSamples, baseViewIndex, numViews); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Attach msrtt-multiview (mMaxIntegerSamples samples) texture to COLOR_ATTACHMENT1 |
| GLTexture colorTexture4; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture4); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numViews, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, colorTexture4, |
| 0, mMaxIntegerSamples, baseViewIndex, numViews); |
| // Draw a quad |
| glClear(GL_COLOR_BUFFER_BIT); |
| drawQuad(program, "a_position", 0.5f, 0.5f, true); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify draw result |
| glBindFramebuffer(GL_FRAMEBUFFER, verifyFbo); |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture3, 0, |
| baseViewIndex); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 2, GLColor::red); |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture3, 0, |
| baseViewIndex + 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 2, GLColor::green); |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture4, 0, |
| baseViewIndex); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 2, GLColor::yellow); |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture4, 0, |
| baseViewIndex + 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 2, GLColor::blue); |
| } |
| |
| // Test that framebuffer fails completeness check if the attachments created with |
| // glFramebufferTextureMultisampleMultiviewOVR() have different render-to-texture sample counts |
| TEST_P(MultiviewMSRTTES3Test, FBOAttachmentsWithDifferentSampleCountShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| constexpr GLsizei multisampleRenderToTextureSampleSize4 = 4; |
| ANGLE_SKIP_TEST_IF(mMaxIntegerSamples <= multisampleRenderToTextureSampleSize4); |
| |
| constexpr int numViews = 2; |
| constexpr int baseViewIndex = 0; |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| // Attach msrtt-multiview (4 samples) texture to COLOR_ATTACHMENT0 |
| GLTexture colorTexture0; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture0); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numViews, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture0, |
| 0, multisampleRenderToTextureSampleSize4, |
| baseViewIndex, numViews); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Attach msrtt-multiview (2 samples) texture to COLOR_ATTACHMENT1 |
| GLTexture colorTexture1; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture1); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numViews, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, colorTexture1, |
| 0, mMaxIntegerSamples, baseViewIndex, numViews); |
| EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, |
| glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| } |
| |
| // Test that framebuffer fails completeness check if the attachments created with |
| // glFramebufferTextureMultisampleMultiviewOVR() have different numViews |
| TEST_P(MultiviewMSRTTES3Test, FBOAttachmentsWithDifferentNumViewsShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| constexpr int multisampleRenderToTextureNumViews1 = 1; |
| ANGLE_SKIP_TEST_IF(mMaxViewsOVR <= multisampleRenderToTextureNumViews1); |
| |
| constexpr GLsizei samples = 2; |
| constexpr int baseViewIndex = 0; |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| // Attach a texture with numViews as 1 to COLOR_ATTACHMENT0 |
| GLTexture colorTexture0; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture0); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, |
| multisampleRenderToTextureNumViews1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture0, |
| 0, samples, baseViewIndex, |
| multisampleRenderToTextureNumViews1); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Attach a texture with numViews as max to COLOR_ATTACHMENT1 |
| GLTexture colorTexture1; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture1); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, mMaxViewsOVR, 0, |
| GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, colorTexture1, |
| 0, samples, baseViewIndex, mMaxViewsOVR); |
| EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR, |
| glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| } |
| |
| // Test that if the layout qualifier num_views is declared more than once in the same shader, |
| // all those declarations must set num_views to the same value; otherwise a compile-time error |
| // results. |
| TEST_P(MultiviewMSRTTES3Test, ConflictingNumViewsDeclarationsShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| const std::string vsSource = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| layout(num_views = 2) in; |
| layout(num_views = 3) in; // Conflicting declaration |
| in vec4 a_position; |
| void main() |
| { |
| gl_Position = a_position; |
| } |
| )"; |
| const std::string fsSource = R"(#version 300 es |
| precision mediump float; |
| out vec4 FragColor; |
| void main() |
| { |
| FragColor = vec4(1.0, 0.0, 0.0, 1.0); |
| } |
| )"; |
| |
| // Expect program compilation/linking to fail due to conflicting num_views |
| GLuint program = CompileProgram(vsSource.c_str(), fsSource.c_str()); |
| EXPECT_EQ(0u, program); |
| } |
| |
| // Test that it is a compile-time error to declare num_views to be less than or equal to zero. |
| TEST_P(MultiviewMSRTTES3Test, NumViewsLessThanOrEqualToZeroShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| // Test with num_views = 0 |
| const std::string vsSourceZero = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| layout(num_views = 0) in; |
| in vec4 a_position; |
| void main() |
| { |
| gl_Position = a_position; |
| } |
| )"; |
| |
| GLuint vs1 = CompileShader(GL_VERTEX_SHADER, vsSourceZero.c_str()); |
| ASSERT(vs1 == 0); |
| |
| // Test with num_views = -1 |
| const std::string vsSourceNegative = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| layout(num_views = -1) in; |
| in vec4 a_position; |
| void main() |
| { |
| gl_Position = a_position; |
| } |
| )"; |
| GLuint vs2 = CompileShader(GL_VERTEX_SHADER, vsSourceNegative.c_str()); |
| ASSERT(vs2 == 0); |
| glDeleteShader(vs1); |
| glDeleteShader(vs2); |
| } |
| |
| // Test that it is a compile-time error to declare num_views to be greater than MAX_VIEWS_OVR. |
| TEST_P(MultiviewMSRTTES3Test, NumViewsGreaterThanMaxViewsOVRShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| // Use mMaxViewsOVR + 1 for the num_views declaration |
| std::string vsSource = "#version 300 es\n"; |
| vsSource += " #extension GL_OVR_multiview : require\n"; |
| vsSource += " layout(num_views = " + std::to_string(mMaxViewsOVR + 1) + ") in;\n"; |
| vsSource += " in vec4 a_position;\n"; |
| vsSource += " void main()\n"; |
| vsSource += " {\n"; |
| vsSource += " gl_Position = a_position;\n"; |
| vsSource += " }\n"; |
| |
| GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource.c_str()); |
| ASSERT(vs == 0); |
| glDeleteShader(vs); |
| } |
| |
| // Test that when attaching 2D array texture to FBO with |
| // glFramebufferTextureMultisampleMultiviewOVR(), glClear() will apply clear color to all views. |
| TEST_P(MultiviewMSRTTES3Test, ClearAppliesToAllViewsInMultiviewFramebuffer) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| constexpr int numViews = 2; |
| constexpr int baseViewIndex = 0; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| |
| GLTexture colorTexture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numViews, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, |
| 0, multisampleRenderToTextureSampleSize, |
| baseViewIndex, numViews); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Set a clear color (e.g., red) |
| GLColor clearColor(255, 0, 0, 255); |
| glClearColor(clearColor.R / 255.0f, clearColor.G / 255.0f, clearColor.B / 255.0f, |
| clearColor.A / 255.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verify that all views are cleared to the specified color |
| GLFramebuffer verifyFbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, verifyFbo); |
| |
| for (int i = 0; i < numViews; ++i) |
| { |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, 0, |
| baseViewIndex + i); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 2, clearColor); |
| } |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that INVALID_OPERATION is generated for a draw operation when the draw framebuffer is |
| // multiview and transform feedback is active. |
| TEST_P(MultiviewMSRTTES3Test, MultiviewDrawFramebufferWithTransformFeedbackShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| // Create a multiview draw framebuffer |
| GLFramebuffer drawFbo; |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFbo); |
| |
| constexpr int numViews = 2; |
| constexpr int baseViewIndex = 0; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| |
| GLTexture drawColorTexture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, drawColorTexture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numViews, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR( |
| GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, drawColorTexture, 0, |
| multisampleRenderToTextureSampleSize, baseViewIndex, numViews); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER); |
| |
| // Create a program with transform feedback varyings |
| const std::string vsSource = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| layout(num_views = 2) in; |
| in vec4 a_position; |
| out vec4 xfb_position; |
| void main() |
| { |
| gl_Position = a_position; |
| xfb_position = a_position; |
| } |
| )"; |
| const std::string fsSource = R"(#version 300 es |
| precision mediump float; |
| out vec4 FragColor; |
| void main() |
| { |
| FragColor = vec4(1.0, 0.0, 0.0, 1.0); |
| } |
| )"; |
| |
| std::vector<std::string> varyings = {"xfb_position"}; |
| ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(program, vsSource.c_str(), fsSource.c_str(), varyings, |
| GL_INTERLEAVED_ATTRIBS); |
| glUseProgram(program); |
| |
| // Create transform feedback buffer |
| GLBuffer transformFeedbackBuffer; |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, transformFeedbackBuffer); |
| glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(GLfloat) * 4 * 3, nullptr, GL_STREAM_READ); |
| glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, transformFeedbackBuffer); |
| |
| // Begin transform feedback |
| glBeginTransformFeedback(GL_TRIANGLES); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Attempt a draw operation with transform feedback active and multiview framebuffer |
| drawQuad(program, "a_position", 0.5f, 0.5f, true); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| |
| glEndTransformFeedback(); |
| glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); |
| } |
| |
| // Test that instanced drawing commands work with multiview. |
| TEST_P(MultiviewMSRTTES3Test, InstancedDrawingWithMultiview) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| const std::string vsSource = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| layout(num_views = 2) in; |
| in vec4 a_position; |
| void main() |
| { |
| gl_Position = a_position; |
| if (gl_InstanceID == 1) { |
| gl_Position.y = gl_Position.y * 0.5 + 0.5; |
| } else { |
| gl_Position.y = gl_Position.y * 0.5 - 0.5; |
| } |
| } |
| )"; |
| const std::string fsSource = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| precision mediump float; |
| out vec4 FragColor; |
| void main() |
| { |
| if (gl_ViewID_OVR == 0u) |
| { |
| FragColor = vec4(0.0, 1.0, 0.0, 1.0); // Green for view 0 |
| } |
| else |
| { |
| FragColor = vec4(1.0, 0.0, 0.0, 1.0); // Red for view 1 |
| } |
| } |
| |
| )"; |
| ANGLE_GL_PROGRAM(program, vsSource.c_str(), fsSource.c_str()); |
| glUseProgram(program); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| constexpr int numViews = 2; |
| constexpr int baseViewIndex = 0; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| |
| GLTexture colorTexture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, colorTexture); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numViews, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, |
| 0, multisampleRenderToTextureSampleSize, |
| baseViewIndex, numViews); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| // Draw 2 instance |
| drawQuadInstanced(program, "a_position", 0.5f, 0.5f, true, 2); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verification |
| GLFramebuffer verifyFbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, verifyFbo); |
| |
| // Verify view 0 (should be green) |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, 0, |
| baseViewIndex + 0); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| // verify first instance |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 4, GLColor::green); |
| // verify second instance |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize * 3 / 4, GLColor::green); |
| |
| // Verify view 1 (should be red) |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, 0, |
| baseViewIndex + 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| // verify first instance |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize / 4, GLColor::red); |
| // verify second instance |
| EXPECT_PIXEL_COLOR_EQ(kWindowSize / 2, kWindowSize * 3 / 4, GLColor::red); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test that rendering to a mipmap level of a 2D array texture works. |
| TEST_P(MultiviewMSRTTES3Test, RenderToMipmapLevel1) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| const std::string vsSource = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| layout(num_views = 2) in; |
| in vec4 a_position; |
| void main() |
| { |
| gl_Position = a_position; |
| } |
| )"; |
| const std::string fsSource = R"(#version 300 es |
| #extension GL_OVR_multiview : require |
| precision mediump float; |
| out vec4 FragColor; |
| void main() |
| { |
| if (gl_ViewID_OVR == 0u) { |
| FragColor = vec4(0.0, 1.0, 0.0, 1.0); // Green for view 0 |
| } else { |
| FragColor = vec4(1.0, 1.0, 0.0, 1.0); // Yellow for view 1 |
| } |
| } |
| )"; |
| |
| ANGLE_GL_PROGRAM(program, vsSource.c_str(), fsSource.c_str()); |
| glUseProgram(program); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| constexpr int numViews = 2; |
| constexpr int baseViewIndex = 0; |
| constexpr GLsizei samples = 4; |
| constexpr int mipmapLevels = 2; |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); |
| glTexStorage3D(GL_TEXTURE_2D_ARRAY, mipmapLevels, GL_RGBA8, kWindowSize, kWindowSize, 2); |
| |
| // Initialize mipmap level 0 with red |
| std::vector<GLColor> level0Data(kWindowSize * kWindowSize * numViews, GLColor::red); |
| glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWindowSize, kWindowSize, numViews, GL_RGBA, |
| GL_UNSIGNED_BYTE, level0Data.data()); |
| |
| // Initialize mipmap level 1 with blue |
| constexpr int mipLevel1Size = kWindowSize >> 1; |
| std::vector<GLColor> level1Data(mipLevel1Size * mipLevel1Size * numViews, GLColor::blue); |
| glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 1, 0, 0, 0, mipLevel1Size, mipLevel1Size, numViews, |
| GL_RGBA, GL_UNSIGNED_BYTE, level1Data.data()); |
| |
| // Attachm mipLevel 1 of the texture array to the FBO |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 1, |
| samples, baseViewIndex, numViews); |
| ASSERT_GL_NO_ERROR(); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Draw a quad |
| glViewport(0, 0, mipLevel1Size, mipLevel1Size); |
| drawQuad(program, "a_position", 0.5f, 0.5f, true); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Verification |
| GLFramebuffer verifyFbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, verifyFbo); |
| |
| // Verify mipmap level 0 is unchanged (should be red) |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, baseViewIndex); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(mipLevel1Size / 2, mipLevel1Size / 2, GLColor::red); |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, baseViewIndex + 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| EXPECT_PIXEL_COLOR_EQ(mipLevel1Size / 2, mipLevel1Size / 2, GLColor::red); |
| |
| // Verify mipmap level 1 is changed (outer edge is blue, inner quad on layer 0 is green, inner |
| // quad on layer 1 is yellow) |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 1, baseViewIndex); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(mipLevel1Size / 2, mipLevel1Size / 2, GLColor::green); |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 1, baseViewIndex + 1); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| EXPECT_PIXEL_COLOR_EQ(mipLevel1Size / 2, mipLevel1Size / 2, GLColor::yellow); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| class MultiviewMSRTTES31Test : public MultiviewMSRTTTest |
| {}; |
| |
| // Test that it is invalid to attach a 2d array texture to the framebuffer with |
| // glFramebufferTextureMultisampleMultiviewOVR and then attach a multisampled texture that is |
| // created with glTexStorage2DMultisample() to the same framebuffer. |
| TEST_P(MultiviewMSRTTES31Test, |
| FramebufferTextureMultisampleMultiviewOVRInvalidAttachmentsShouldFail) |
| { |
| ANGLE_SKIP_TEST_IF( |
| !EnsureGLExtensionEnabled("GL_OVR_multiview_multisampled_render_to_texture")); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| constexpr int numLayers = 2; |
| constexpr GLsizei multisampleRenderToTextureSampleSize = 4; |
| |
| // Attach a 2D array texture with glFramebufferTextureMultisampleMultiviewOVR |
| GLTexture textureArray; |
| glBindTexture(GL_TEXTURE_2D_ARRAY, textureArray); |
| glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, kWindowSize, kWindowSize, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, nullptr); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureArray, |
| 0, multisampleRenderToTextureSampleSize, 0, |
| numLayers); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Attempt to attach a multisample texture created with glTexStorage2DMultisample to the same |
| // Framebuffer should fail |
| GLTexture textureMultisample; |
| glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureMultisample); |
| glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, multisampleRenderToTextureSampleSize, |
| GL_RGBA8, kWindowSize, kWindowSize, GL_TRUE); |
| glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, |
| textureMultisample, 0, |
| multisampleRenderToTextureSampleSize, 0, numLayers); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewMSRTTES3Test); |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewMSRTTES31Test); |
| |
| ANGLE_INSTANTIATE_TEST_ES3(MultiviewMSRTTES3Test); |
| ANGLE_INSTANTIATE_TEST_ES31(MultiviewMSRTTES31Test); |
| |
| } // namespace |