Commit 8acb1b61 by Olli Etuaho Committed by Commit Bot

Allow reads from a multiview framebuffer with one view

It's safe to read from a multiview framebuffer if it is layered and has just one view. The native OVR_multiview spec supports this as well. BUG=angleproject:2062 TEST=angle_end2end_tests Change-Id: I04e1364390574075f7e06e39a64e3bf05a539a05 Reviewed-on: https://chromium-review.googlesource.com/1156509 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 2eb65034
...@@ -24,7 +24,7 @@ Status ...@@ -24,7 +24,7 @@ Status
Version Version
Last Modified Date: July 14, 2017 Last Modified Date: July 31, 2018
Author Revision: 1 Author Revision: 1
Number Number
...@@ -128,7 +128,9 @@ Additions to Chapter 3 of the OpenGL ES 3.0 Specification (Rasterization) ...@@ -128,7 +128,9 @@ Additions to Chapter 3 of the OpenGL ES 3.0 Specification (Rasterization)
"Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will "Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will
result in an INVALID_FRAMEBUFFER_OPERATION error if the multi-view result in an INVALID_FRAMEBUFFER_OPERATION error if the multi-view
layout of the current read framebuffer is not NONE." layout of the current read framebuffer is
FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of views in the
current read framebuffer is more than one."
Additions to Chapter 4 of the OpenGL ES 3.0 Specification Additions to Chapter 4 of the OpenGL ES 3.0 Specification
(Per-Fragment Operations and the Framebuffer) (Per-Fragment Operations and the Framebuffer)
...@@ -169,7 +171,9 @@ Additions to Chapter 4 of the OpenGL ES 3.0 Specification ...@@ -169,7 +171,9 @@ Additions to Chapter 4 of the OpenGL ES 3.0 Specification
Add to the end of the section: Add to the end of the section:
" ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if " ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if
the multi-view layout of the current read framebuffer is not NONE." the multi-view layout of the current read framebuffer is
FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of views in the
current read framebuffer is more than one."
Modify section 4.3.3 (Copying pixels), p. 198 Modify section 4.3.3 (Copying pixels), p. 198
...@@ -181,8 +185,10 @@ Additions to Chapter 4 of the OpenGL ES 3.0 Specification ...@@ -181,8 +185,10 @@ Additions to Chapter 4 of the OpenGL ES 3.0 Specification
add a new paragraph: add a new paragraph:
"Calling BlitFramebuffer will result in an INVALID_FRAMEBUFFER_OPERATION "Calling BlitFramebuffer will result in an INVALID_FRAMEBUFFER_OPERATION
error if the multi-view layout of the current draw framebuffer or error if the multi-view layout of the current draw framebuffer is not NONE,
read framebuffer is not NONE." or the multi-view layout of the current read framebuffer is
FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, or the number of views in the
current read framebuffer is more than one."
Modify section 4.4.2 (Attaching Images to Framebuffer Objects), p. 202 Modify section 4.4.2 (Attaching Images to Framebuffer Objects), p. 202
......
...@@ -2057,6 +2057,12 @@ GLenum Framebuffer::getMultiviewLayout() const ...@@ -2057,6 +2057,12 @@ GLenum Framebuffer::getMultiviewLayout() const
return mState.getMultiviewLayout(); return mState.getMultiviewLayout();
} }
bool Framebuffer::readDisallowedByMultiview() const
{
return (mState.getMultiviewLayout() != GL_NONE && mState.getNumViews() > 1) ||
mState.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE;
}
Error Framebuffer::ensureClearAttachmentsInitialized(const Context *context, GLbitfield mask) Error Framebuffer::ensureClearAttachmentsInitialized(const Context *context, GLbitfield mask)
{ {
const auto &glState = context->getGLState(); const auto &glState = context->getGLState();
......
...@@ -195,6 +195,7 @@ class Framebuffer final : public angle::ObserverInterface, public LabeledObject ...@@ -195,6 +195,7 @@ class Framebuffer final : public angle::ObserverInterface, public LabeledObject
const FramebufferAttachment *getAttachment(const Context *context, GLenum attachment) const; const FramebufferAttachment *getAttachment(const Context *context, GLenum attachment) const;
GLenum getMultiviewLayout() const; GLenum getMultiviewLayout() const;
bool readDisallowedByMultiview() const;
GLsizei getNumViews() const; GLsizei getNumViews() const;
GLint getBaseViewIndex() const; GLint getBaseViewIndex() const;
const std::vector<Offset> *getViewportOffsets() const; const std::vector<Offset> *getViewportOffsets() const;
......
...@@ -1506,8 +1506,10 @@ bool ValidateBlitFramebufferParameters(Context *context, ...@@ -1506,8 +1506,10 @@ bool ValidateBlitFramebufferParameters(Context *context,
// ANGLE_multiview, Revision 1: // ANGLE_multiview, Revision 1:
// Calling BlitFramebuffer will result in an INVALID_FRAMEBUFFER_OPERATION error if the // Calling BlitFramebuffer will result in an INVALID_FRAMEBUFFER_OPERATION error if the
// multi-view layout of the current draw framebuffer or read framebuffer is not NONE. // multi-view layout of the current draw framebuffer is not NONE, or if the multi-view layout of
if (readFramebuffer->getMultiviewLayout() != GL_NONE) // the current read framebuffer is FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of
// views in the current read framebuffer is more than one.
if (readFramebuffer->readDisallowedByMultiview())
{ {
context->handleError(InvalidFramebufferOperation() context->handleError(InvalidFramebufferOperation()
<< "Attempt to read from a multi-view framebuffer."); << "Attempt to read from a multi-view framebuffer.");
...@@ -2522,8 +2524,9 @@ bool ValidateCopyTexImageParametersBase(Context *context, ...@@ -2522,8 +2524,9 @@ bool ValidateCopyTexImageParametersBase(Context *context,
// ANGLE_multiview spec, Revision 1: // ANGLE_multiview spec, Revision 1:
// Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will result in an // Calling CopyTexSubImage3D, CopyTexImage2D, or CopyTexSubImage2D will result in an
// INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the current read framebuffer // INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the current read framebuffer
// is not NONE. // is FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of views in the current read
if (source->getMultiviewLayout() != GL_NONE) // framebuffer is more than one.
if (readFramebuffer->readDisallowedByMultiview())
{ {
context->handleError(InvalidFramebufferOperation() context->handleError(InvalidFramebufferOperation()
<< "The active read framebuffer object has multiview attachments."); << "The active read framebuffer object has multiview attachments.");
...@@ -5707,8 +5710,9 @@ bool ValidateReadPixelsBase(Context *context, ...@@ -5707,8 +5710,9 @@ bool ValidateReadPixelsBase(Context *context,
// ANGLE_multiview, Revision 1: // ANGLE_multiview, Revision 1:
// ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the // ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the
// current read framebuffer is not NONE. // current read framebuffer is FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of views
if (readBuffer->getMultiviewLayout() != GL_NONE) // in the current read framebuffer is more than one.
if (framebuffer->readDisallowedByMultiview())
{ {
context->handleError(InvalidFramebufferOperation() context->handleError(InvalidFramebufferOperation()
<< "Attempting to read from a multi-view framebuffer."); << "Attempting to read from a multi-view framebuffer.");
......
...@@ -53,7 +53,6 @@ class FramebufferMultiviewTest : public ANGLETest ...@@ -53,7 +53,6 @@ class FramebufferMultiviewTest : public ANGLETest
if (!extensionEnabled("GL_ANGLE_multiview")) if (!extensionEnabled("GL_ANGLE_multiview"))
{ {
std::cout << "Test skipped due to missing GL_ANGLE_multiview." << std::endl;
return false; return false;
} }
return true; return true;
...@@ -278,10 +277,7 @@ class FramebufferMultiviewLayeredClearTest : public FramebufferMultiviewTest ...@@ -278,10 +277,7 @@ class FramebufferMultiviewLayeredClearTest : public FramebufferMultiviewTest
// framebuffer state and that their corresponding default values are correctly set. // framebuffer state and that their corresponding default values are correctly set.
TEST_P(FramebufferMultiviewTest, DefaultState) TEST_P(FramebufferMultiviewTest, DefaultState)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
GLFramebuffer fbo; GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
...@@ -362,10 +358,7 @@ TEST_P(FramebufferMultiviewTest, NegativeFramebufferStateQueries) ...@@ -362,10 +358,7 @@ TEST_P(FramebufferMultiviewTest, NegativeFramebufferStateQueries)
// is called with invalid arguments. // is called with invalid arguments.
TEST_P(FramebufferMultiviewTest, InvalidMultiviewSideBySideArguments) TEST_P(FramebufferMultiviewTest, InvalidMultiviewSideBySideArguments)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
GLFramebuffer fbo; GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
...@@ -392,10 +385,7 @@ TEST_P(FramebufferMultiviewTest, InvalidMultiviewSideBySideArguments) ...@@ -392,10 +385,7 @@ TEST_P(FramebufferMultiviewTest, InvalidMultiviewSideBySideArguments)
// called with invalid arguments. // called with invalid arguments.
TEST_P(FramebufferMultiviewTest, InvalidMultiviewLayeredArguments) TEST_P(FramebufferMultiviewTest, InvalidMultiviewLayeredArguments)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
GLFramebuffer fbo; GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
...@@ -438,10 +428,7 @@ TEST_P(FramebufferMultiviewTest, ExtensionNotAvailableCheck) ...@@ -438,10 +428,7 @@ TEST_P(FramebufferMultiviewTest, ExtensionNotAvailableCheck)
// Test that glFramebufferTextureMultiviewSideBySideANGLE modifies the internal multiview state. // Test that glFramebufferTextureMultiviewSideBySideANGLE modifies the internal multiview state.
TEST_P(FramebufferMultiviewTest, ModifySideBySideState) TEST_P(FramebufferMultiviewTest, ModifySideBySideState)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
GLFramebuffer fbo; GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
...@@ -491,10 +478,7 @@ TEST_P(FramebufferMultiviewTest, ModifySideBySideState) ...@@ -491,10 +478,7 @@ TEST_P(FramebufferMultiviewTest, ModifySideBySideState)
// attachments. // attachments.
TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsSideBySide) TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsSideBySide)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
GLFramebuffer fbo; GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
...@@ -587,13 +571,10 @@ TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsSideBySide) ...@@ -587,13 +571,10 @@ TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsSideBySide)
} }
// Test that the active read framebuffer cannot be read from through glCopyTex* if it has multi-view // Test that the active read framebuffer cannot be read from through glCopyTex* if it has multi-view
// attachments. // attachments with a side-by-side layout.
TEST_P(FramebufferMultiviewTest, InvalidCopyTex) TEST_P(FramebufferMultiviewTest, InvalidCopyTex)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
GLFramebuffer fbo; GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
...@@ -631,14 +612,77 @@ TEST_P(FramebufferMultiviewTest, InvalidCopyTex) ...@@ -631,14 +612,77 @@ TEST_P(FramebufferMultiviewTest, InvalidCopyTex)
} }
} }
// Test that glBlitFramebuffer generates an invalid framebuffer operation when either the current // Test that the active read framebuffer can be read with glCopyTex* if it only has one layered
// draw framebuffer, or current read framebuffer have multiview attachments. // view.
TEST_P(FramebufferMultiviewTest, InvalidBlit) TEST_P(FramebufferMultiviewTest, CopyTex)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLTexture tex;
glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTextureMultiviewLayeredANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 0, 1);
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
ASSERT_GL_NO_ERROR();
// Test glCopyTexImage2D and glCopyTexSubImage2D.
{
GLTexture tex2;
glBindTexture(GL_TEXTURE_2D, tex2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, 1, 1, 0);
ASSERT_GL_NO_ERROR();
// Test texture contents.
glBindFramebuffer(GL_FRAMEBUFFER, 0);
draw2DTexturedQuad(0.0f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
draw2DTexturedQuad(0.0f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
}
// Test glCopyTexSubImage3D.
{ {
return; GLTexture tex2;
glBindTexture(GL_TEXTURE_3D, tex2);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 1, 1);
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
draw3DTexturedQuad(0.0f, 1.0f, true, 0.0f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
} }
}
// Test that glBlitFramebuffer generates an invalid framebuffer operation when either the current
// draw framebuffer, or current read framebuffer have multiview attachments with a side-by-side
// layout.
TEST_P(FramebufferMultiviewTest, InvalidBlit)
{
ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
GLFramebuffer fbo; GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
...@@ -670,14 +714,42 @@ TEST_P(FramebufferMultiviewTest, InvalidBlit) ...@@ -670,14 +714,42 @@ TEST_P(FramebufferMultiviewTest, InvalidBlit)
} }
} }
// Test that glBlitFramebuffer succeeds if the current read framebuffer has just one layered view.
TEST_P(FramebufferMultiviewTest, Blit)
{
ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLTexture tex;
glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTextureMultiviewLayeredANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 0, 1);
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
ASSERT_GL_NO_ERROR();
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test that glReadPixels generates an invalid framebuffer operation error if the current read // Test that glReadPixels generates an invalid framebuffer operation error if the current read
// framebuffer has a multi-view layout. // framebuffer has a side-by-side multi-view layout.
TEST_P(FramebufferMultiviewTest, InvalidReadPixels) TEST_P(FramebufferMultiviewTest, InvalidReadPixels)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
GLFramebuffer fbo; GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
...@@ -697,13 +769,35 @@ TEST_P(FramebufferMultiviewTest, InvalidReadPixels) ...@@ -697,13 +769,35 @@ TEST_P(FramebufferMultiviewTest, InvalidReadPixels)
EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION); EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
} }
// Test that glReadPixels succeeds from a layered multiview framebuffer with just one view.
TEST_P(FramebufferMultiviewTest, ReadPixels)
{
ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLTexture tex;
glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTextureMultiviewLayeredANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 0, 1);
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
ASSERT_GL_NO_ERROR();
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLColor pixelColor;
glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixelColor.R);
ASSERT_GL_NO_ERROR();
EXPECT_COLOR_NEAR(GLColor::green, pixelColor, 2);
}
// Test that glClear clears only the contents of each view if the scissor test is enabled. // Test that glClear clears only the contents of each view if the scissor test is enabled.
TEST_P(FramebufferMultiviewSideBySideClearTest, ColorBufferClear) TEST_P(FramebufferMultiviewSideBySideClearTest, ColorBufferClear)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
initializeFBOs(1, false, false); initializeFBOs(1, false, false);
...@@ -729,10 +823,7 @@ TEST_P(FramebufferMultiviewSideBySideClearTest, ColorBufferClear) ...@@ -729,10 +823,7 @@ TEST_P(FramebufferMultiviewSideBySideClearTest, ColorBufferClear)
// Test that glFramebufferTextureMultiviewLayeredANGLE modifies the internal multiview state. // Test that glFramebufferTextureMultiviewLayeredANGLE modifies the internal multiview state.
TEST_P(FramebufferMultiviewTest, ModifyLayeredState) TEST_P(FramebufferMultiviewTest, ModifyLayeredState)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
GLFramebuffer multiviewFBO; GLFramebuffer multiviewFBO;
glBindFramebuffer(GL_FRAMEBUFFER, multiviewFBO); glBindFramebuffer(GL_FRAMEBUFFER, multiviewFBO);
...@@ -778,10 +869,7 @@ TEST_P(FramebufferMultiviewTest, ModifyLayeredState) ...@@ -778,10 +869,7 @@ TEST_P(FramebufferMultiviewTest, ModifyLayeredState)
// Test framebuffer completeness status of a layered framebuffer with color attachments. // Test framebuffer completeness status of a layered framebuffer with color attachments.
TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsLayered) TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsLayered)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
GLFramebuffer fbo; GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
...@@ -834,10 +922,7 @@ TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsLayered) ...@@ -834,10 +922,7 @@ TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsLayered)
// Test that glClear clears all of the contents if the scissor test is disabled. // Test that glClear clears all of the contents if the scissor test is disabled.
TEST_P(FramebufferMultiviewSideBySideClearTest, ClearWithDisabledScissorTest) TEST_P(FramebufferMultiviewSideBySideClearTest, ClearWithDisabledScissorTest)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
initializeFBOs(1, false, false); initializeFBOs(1, false, false);
...@@ -868,10 +953,7 @@ TEST_P(FramebufferMultiviewSideBySideClearTest, ClearWithDisabledScissorTest) ...@@ -868,10 +953,7 @@ TEST_P(FramebufferMultiviewSideBySideClearTest, ClearWithDisabledScissorTest)
// Test that glClear clears the depth buffer of each view. // Test that glClear clears the depth buffer of each view.
TEST_P(FramebufferMultiviewSideBySideClearTest, DepthBufferClear) TEST_P(FramebufferMultiviewSideBySideClearTest, DepthBufferClear)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
// Create program to draw a quad. // Create program to draw a quad.
const std::string &vs = const std::string &vs =
...@@ -924,10 +1006,7 @@ TEST_P(FramebufferMultiviewSideBySideClearTest, DepthBufferClear) ...@@ -924,10 +1006,7 @@ TEST_P(FramebufferMultiviewSideBySideClearTest, DepthBufferClear)
// Test that glClear clears the stencil buffer of each view. // Test that glClear clears the stencil buffer of each view.
TEST_P(FramebufferMultiviewSideBySideClearTest, StencilBufferClear) TEST_P(FramebufferMultiviewSideBySideClearTest, StencilBufferClear)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
// Create program to draw a quad. // Create program to draw a quad.
const std::string &vs = const std::string &vs =
...@@ -988,10 +1067,7 @@ TEST_P(FramebufferMultiviewSideBySideClearTest, StencilBufferClear) ...@@ -988,10 +1067,7 @@ TEST_P(FramebufferMultiviewSideBySideClearTest, StencilBufferClear)
// Test that glClearBufferf clears the color buffer of each view. // Test that glClearBufferf clears the color buffer of each view.
TEST_P(FramebufferMultiviewSideBySideClearTest, ClearBufferF) TEST_P(FramebufferMultiviewSideBySideClearTest, ClearBufferF)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
initializeFBOs(2, false, false); initializeFBOs(2, false, false);
...@@ -1030,10 +1106,7 @@ TEST_P(FramebufferMultiviewSideBySideClearTest, ClearBufferF) ...@@ -1030,10 +1106,7 @@ TEST_P(FramebufferMultiviewSideBySideClearTest, ClearBufferF)
// layered FBO. // layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest, ColorBufferClear) TEST_P(FramebufferMultiviewLayeredClearTest, ColorBufferClear)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
initializeFBOs(1, 1, 4, 1, 2, 1, false, false); initializeFBOs(1, 1, 4, 1, 2, 1, false, false);
...@@ -1052,10 +1125,7 @@ TEST_P(FramebufferMultiviewLayeredClearTest, ColorBufferClear) ...@@ -1052,10 +1125,7 @@ TEST_P(FramebufferMultiviewLayeredClearTest, ColorBufferClear)
// Test that glClearBufferfv can be used to clear individual color buffers of a layered FBO. // Test that glClearBufferfv can be used to clear individual color buffers of a layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest, ClearIndividualColorBuffer) TEST_P(FramebufferMultiviewLayeredClearTest, ClearIndividualColorBuffer)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
initializeFBOs(1, 1, 4, 1, 2, 2, false, false); initializeFBOs(1, 1, 4, 1, 2, 2, false, false);
...@@ -1091,10 +1161,7 @@ TEST_P(FramebufferMultiviewLayeredClearTest, ClearIndividualColorBuffer) ...@@ -1091,10 +1161,7 @@ TEST_P(FramebufferMultiviewLayeredClearTest, ClearIndividualColorBuffer)
// to a layered FBO. // to a layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest, ClearBufferfi) TEST_P(FramebufferMultiviewLayeredClearTest, ClearBufferfi)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
// Create program to draw a quad. // Create program to draw a quad.
const std::string &vs = const std::string &vs =
...@@ -1153,10 +1220,7 @@ TEST_P(FramebufferMultiviewLayeredClearTest, ClearBufferfi) ...@@ -1153,10 +1220,7 @@ TEST_P(FramebufferMultiviewLayeredClearTest, ClearBufferfi)
// Test that glClear does not clear the content of a detached texture. // Test that glClear does not clear the content of a detached texture.
TEST_P(FramebufferMultiviewLayeredClearTest, UnmodifiedDetachedTexture) TEST_P(FramebufferMultiviewLayeredClearTest, UnmodifiedDetachedTexture)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
initializeFBOs(1, 1, 4, 1, 2, 2, false, false); initializeFBOs(1, 1, 4, 1, 2, 2, false, false);
...@@ -1196,10 +1260,7 @@ TEST_P(FramebufferMultiviewLayeredClearTest, UnmodifiedDetachedTexture) ...@@ -1196,10 +1260,7 @@ TEST_P(FramebufferMultiviewLayeredClearTest, UnmodifiedDetachedTexture)
// Test that glClear clears only the contents within the scissor rectangle of the attached layers. // Test that glClear clears only the contents within the scissor rectangle of the attached layers.
TEST_P(FramebufferMultiviewLayeredClearTest, ScissoredClear) TEST_P(FramebufferMultiviewLayeredClearTest, ScissoredClear)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
initializeFBOs(2, 1, 4, 1, 2, 1, false, false); initializeFBOs(2, 1, 4, 1, 2, 1, false, false);
...@@ -1228,10 +1289,7 @@ TEST_P(FramebufferMultiviewLayeredClearTest, ScissoredClear) ...@@ -1228,10 +1289,7 @@ TEST_P(FramebufferMultiviewLayeredClearTest, ScissoredClear)
// to a layered FBO. // to a layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest, ScissoredClearBufferfi) TEST_P(FramebufferMultiviewLayeredClearTest, ScissoredClearBufferfi)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
// Create program to draw a quad. // Create program to draw a quad.
const std::string &vs = const std::string &vs =
...@@ -1298,10 +1356,7 @@ TEST_P(FramebufferMultiviewLayeredClearTest, ScissoredClearBufferfi) ...@@ -1298,10 +1356,7 @@ TEST_P(FramebufferMultiviewLayeredClearTest, ScissoredClearBufferfi)
// arguments are invalid. // arguments are invalid.
TEST_P(FramebufferMultiviewTest, InvalidMultiviewArgumentsOnDetach) TEST_P(FramebufferMultiviewTest, InvalidMultiviewArgumentsOnDetach)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
GLFramebuffer fbo; GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
...@@ -1331,10 +1386,7 @@ TEST_P(FramebufferMultiviewTest, InvalidMultiviewArgumentsOnDetach) ...@@ -1331,10 +1386,7 @@ TEST_P(FramebufferMultiviewTest, InvalidMultiviewArgumentsOnDetach)
// array are attached. The test is added because a special fast code path is used for this case. // array are attached. The test is added because a special fast code path is used for this case.
TEST_P(FramebufferMultiviewLayeredClearTest, ColorBufferClearAllLayersAttached) TEST_P(FramebufferMultiviewLayeredClearTest, ColorBufferClearAllLayersAttached)
{ {
if (!requestMultiviewExtension()) ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
{
return;
}
initializeFBOs(1, 1, 2, 0, 2, 1, false, false); initializeFBOs(1, 1, 2, 0, 2, 1, false, false);
...@@ -1346,6 +1398,6 @@ TEST_P(FramebufferMultiviewLayeredClearTest, ColorBufferClearAllLayersAttached) ...@@ -1346,6 +1398,6 @@ TEST_P(FramebufferMultiviewLayeredClearTest, ColorBufferClearAllLayersAttached)
EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0)); EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0));
} }
ANGLE_INSTANTIATE_TEST(FramebufferMultiviewTest, ES3_OPENGL()); ANGLE_INSTANTIATE_TEST(FramebufferMultiviewTest, ES3_OPENGL(), ES3_D3D11());
ANGLE_INSTANTIATE_TEST(FramebufferMultiviewSideBySideClearTest, ES3_OPENGL(), ES3_D3D11()); ANGLE_INSTANTIATE_TEST(FramebufferMultiviewSideBySideClearTest, ES3_OPENGL(), ES3_D3D11());
ANGLE_INSTANTIATE_TEST(FramebufferMultiviewLayeredClearTest, ES3_OPENGL(), ES3_D3D11()); ANGLE_INSTANTIATE_TEST(FramebufferMultiviewLayeredClearTest, ES3_OPENGL(), ES3_D3D11());
\ No newline at end of file
...@@ -231,6 +231,7 @@ ANGLETestBase::ANGLETestBase(const angle::PlatformParameters &params) ...@@ -231,6 +231,7 @@ ANGLETestBase::ANGLETestBase(const angle::PlatformParameters &params)
mQuadVertexBuffer(0), mQuadVertexBuffer(0),
mQuadIndexBuffer(0), mQuadIndexBuffer(0),
m2DTexturedQuadProgram(0), m2DTexturedQuadProgram(0),
m3DTexturedQuadProgram(0),
mDeferContextInit(false) mDeferContextInit(false)
{ {
mEGLWindow = new EGLWindow(params.majorVersion, params.minorVersion, params.eglParameters); mEGLWindow = new EGLWindow(params.majorVersion, params.minorVersion, params.eglParameters);
...@@ -269,6 +270,10 @@ ANGLETestBase::~ANGLETestBase() ...@@ -269,6 +270,10 @@ ANGLETestBase::~ANGLETestBase()
{ {
glDeleteProgram(m2DTexturedQuadProgram); glDeleteProgram(m2DTexturedQuadProgram);
} }
if (m3DTexturedQuadProgram)
{
glDeleteProgram(m3DTexturedQuadProgram);
}
SafeDelete(mEGLWindow); SafeDelete(mEGLWindow);
} }
...@@ -639,13 +644,72 @@ GLuint ANGLETestBase::get2DTexturedQuadProgram() ...@@ -639,13 +644,72 @@ GLuint ANGLETestBase::get2DTexturedQuadProgram()
return m2DTexturedQuadProgram; return m2DTexturedQuadProgram;
} }
GLuint ANGLETestBase::get3DTexturedQuadProgram()
{
if (m3DTexturedQuadProgram)
{
return m3DTexturedQuadProgram;
}
const std::string &vs =
R"(#version 300 es
in vec2 position;
out vec2 texCoord;
void main()
{
gl_Position = vec4(position, 0, 1);
texCoord = position * 0.5 + vec2(0.5);
})";
const std::string &fs =
R"(#version 300 es
precision highp float;
in vec2 texCoord;
out vec4 my_FragColor;
uniform highp sampler3D tex;
uniform float u_layer;
void main()
{
my_FragColor = texture(tex, vec3(texCoord, u_layer));
})";
m3DTexturedQuadProgram = CompileProgram(vs, fs);
return m3DTexturedQuadProgram;
}
void ANGLETestBase::draw2DTexturedQuad(GLfloat positionAttribZ, void ANGLETestBase::draw2DTexturedQuad(GLfloat positionAttribZ,
GLfloat positionAttribXYScale, GLfloat positionAttribXYScale,
bool useVertexBuffer) bool useVertexBuffer)
{ {
ASSERT_NE(0u, get2DTexturedQuadProgram()); ASSERT_NE(0u, get2DTexturedQuadProgram());
return drawQuad(get2DTexturedQuadProgram(), "position", positionAttribZ, positionAttribXYScale, drawQuad(get2DTexturedQuadProgram(), "position", positionAttribZ, positionAttribXYScale,
useVertexBuffer); useVertexBuffer);
}
void ANGLETestBase::draw3DTexturedQuad(GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useVertexBuffer,
float layer)
{
GLuint program = get3DTexturedQuadProgram();
ASSERT_NE(0u, program);
GLint activeProgram = 0;
glGetIntegerv(GL_CURRENT_PROGRAM, &activeProgram);
if (static_cast<GLuint>(activeProgram) != program)
{
glUseProgram(program);
}
glUniform1f(glGetUniformLocation(program, "u_layer"), layer);
drawQuad(program, "position", positionAttribZ, positionAttribXYScale, useVertexBuffer);
if (static_cast<GLuint>(activeProgram) != program)
{
glUseProgram(static_cast<GLuint>(activeProgram));
}
} }
GLuint ANGLETestBase::compileShader(GLenum type, const std::string &source) GLuint ANGLETestBase::compileShader(GLenum type, const std::string &source)
......
...@@ -314,6 +314,12 @@ class ANGLETestBase ...@@ -314,6 +314,12 @@ class ANGLETestBase
GLfloat positionAttribXYScale, GLfloat positionAttribXYScale,
bool useVertexBuffer); bool useVertexBuffer);
// The layer parameter chooses the 3D texture layer to sample from.
void draw3DTexturedQuad(GLfloat positionAttribZ,
GLfloat positionAttribXYScale,
bool useVertexBuffer,
float layer);
static GLuint compileShader(GLenum type, const std::string &source); static GLuint compileShader(GLenum type, const std::string &source);
static bool extensionEnabled(const std::string &extName); static bool extensionEnabled(const std::string &extName);
static bool extensionRequestable(const std::string &extName); static bool extensionRequestable(const std::string &extName);
...@@ -362,6 +368,9 @@ class ANGLETestBase ...@@ -362,6 +368,9 @@ class ANGLETestBase
GLuint get2DTexturedQuadProgram(); GLuint get2DTexturedQuadProgram();
// Has a float uniform "u_layer" to choose the 3D texture layer.
GLuint get3DTexturedQuadProgram();
angle::PlatformMethods mPlatformMethods; angle::PlatformMethods mPlatformMethods;
class ScopedIgnorePlatformMessages : angle::NonCopyable class ScopedIgnorePlatformMessages : angle::NonCopyable
...@@ -399,6 +408,7 @@ class ANGLETestBase ...@@ -399,6 +408,7 @@ class ANGLETestBase
// Used for texture rendering. // Used for texture rendering.
GLuint m2DTexturedQuadProgram; GLuint m2DTexturedQuadProgram;
GLuint m3DTexturedQuadProgram;
TestPlatformContext mPlatformContext; TestPlatformContext mPlatformContext;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment