Add support for GL_MESA_framebuffer_flip_y 3/*

This is a third CL that adds tests that exercise
the extension in various use cases.

Bug: chromium:1231934
Change-Id: Iae3192cd0985150b6844a2855a9a048a54353655
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3365195
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>
Commit-Queue: Maksim Sisov <msisov@igalia.com>
This commit is contained in:
Maksim Sisov 2022-01-03 13:29:59 +02:00 коммит произвёл Angle LUCI CQ
Родитель a765500786
Коммит 4572a17644
6 изменённых файлов: 956 добавлений и 126 удалений

Просмотреть файл

@ -1801,13 +1801,8 @@ void GenerateCaps(const FunctionsGL *functions,
extensions->YUVTargetEXT = functions->hasGLESExtension("GL_EXT_YUV_target"); extensions->YUVTargetEXT = functions->hasGLESExtension("GL_EXT_YUV_target");
// GL_MESA_framebuffer_flip_y // GL_MESA_framebuffer_flip_y
if (functions->isAtLeastGL(gl::Version(4, 3)) || extensions->framebufferFlipYMESA = functions->hasGLESExtension("GL_MESA_framebuffer_flip_y") ||
functions->hasGLExtension("GL_MESA_framebuffer_flip_y") || functions->hasGLExtension("GL_MESA_framebuffer_flip_y");
functions->isAtLeastGLES(gl::Version(3, 1)) ||
functions->hasGLESExtension("GL_MESA_framebuffer_flip_y"))
{
extensions->framebufferFlipYMESA = true;
}
// GL_KHR_parallel_shader_compile // GL_KHR_parallel_shader_compile
extensions->parallelShaderCompileKHR = true; extensions->parallelShaderCompileKHR = true;

Просмотреть файл

@ -350,6 +350,67 @@ class BlitFramebufferANGLETest : public ANGLETest
return true; return true;
} }
void BlitStencilTestHelper(bool mesaYFlip)
{
glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO);
if (mesaYFlip)
{
ASSERT_TRUE(IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
}
glClearColor(0.0, 1.0, 0.0, 1.0);
glClearStencil(0x0);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Scissor half the screen so we fill the stencil only halfway
glScissor(0, 0, getWindowWidth(), getWindowHeight() / 2);
glEnable(GL_SCISSOR_TEST);
// fill the stencil buffer with 0x1
glStencilFunc(GL_ALWAYS, 0x1, 0xFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glEnable(GL_STENCIL_TEST);
drawQuad(mRedProgram, essl1_shaders::PositionAttrib(), 0.3f);
glDisable(GL_SCISSOR_TEST);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO);
glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO);
// These clears are not useful in theory because we're copying over them, but its
// helpful in debugging if we see white in any result.
glClearColor(1.0, 1.0, 1.0, 1.0);
glClearStencil(0x0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(),
getWindowHeight(), GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
GL_NEAREST);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green);
glStencilFunc(GL_EQUAL, 0x1, 0xFF); // only pass if stencil buffer at pixel reads 0x1
drawQuad(mBlueProgram, essl1_shaders::PositionAttrib(),
0.8f); // blue quad will draw if stencil buffer was copied
glDisable(GL_STENCIL_TEST);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green);
}
GLuint mCheckerProgram; GLuint mCheckerProgram;
GLuint mBlueProgram; GLuint mBlueProgram;
GLuint mRedProgram; GLuint mRedProgram;
@ -501,6 +562,267 @@ TEST_P(BlitFramebufferANGLETest, BlitColorWithFlip)
EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::yellow); EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::yellow);
} }
// Blit color to default framebuffer from another framebuffer with GL_MESA_framebuffer_flip_y.
TEST_P(BlitFramebufferANGLETest, BlitColorWithMesaYFlipSrc)
{
// OpenGL ES 3.0 / GL_NV_framebuffer_blit required for flip.
ANGLE_SKIP_TEST_IF(
(getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_NV_framebuffer_blit")) ||
!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO);
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
EXPECT_GL_NO_ERROR();
drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f);
EXPECT_GL_NO_ERROR();
// Blit to default from y-flipped.
glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO);
const int fboTargetWidth = getWindowHeight() / 2;
const int fboTargetHeight = getWindowHeight() / 2;
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, fboTargetWidth,
fboTargetHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO);
EXPECT_PIXEL_COLOR_EQ(fboTargetWidth / 4, fboTargetHeight / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(fboTargetWidth / 4, 3 * fboTargetHeight / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(3 * fboTargetWidth / 4, fboTargetHeight / 4, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(3 * fboTargetWidth / 4, 3 * fboTargetHeight / 4, GLColor::yellow);
}
// Blit color to y-flipped with GL_MESA_framebuffer_flip_y framebuffer from normal framebuffer.
TEST_P(BlitFramebufferANGLETest, BlitColorWithMesaYFlipDst)
{
// OpenGL ES 3.0 / GL_NV_framebuffer_blit required for flip.
ANGLE_SKIP_TEST_IF(
(getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_NV_framebuffer_blit")) ||
!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f);
EXPECT_GL_NO_ERROR();
// Blit to default from y-flipped.
glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mOriginalFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mUserFBO);
glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER_ANGLE, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
const int fboTargetWidth = getWindowWidth() / 2;
const int fboTargetHeight = getWindowHeight();
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, fboTargetWidth,
fboTargetHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), getWindowWidth() / 2, 0,
getWindowWidth(), getWindowHeight() / 2, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER_ANGLE, GL_FRAMEBUFFER_FLIP_Y_MESA, 0);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO);
// Left side have inverted checker pattern.
EXPECT_PIXEL_COLOR_EQ(fboTargetWidth / 4, fboTargetHeight / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(fboTargetWidth / 4, 3 * fboTargetHeight / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(3 * fboTargetWidth / 4, fboTargetHeight / 4, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(3 * fboTargetWidth / 4, 3 * fboTargetHeight / 4, GLColor::blue);
// Right side is split to 2 parts where upper part have non y-flipped checker pattern and the
// bottom one has white color.
EXPECT_PIXEL_COLOR_EQ(5 * getWindowWidth() / 8, 5 * getWindowHeight() / 8, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(5 * getWindowWidth() / 8, 7 * getWindowHeight() / 8, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(7 * getWindowWidth() / 8, 5 * getWindowHeight() / 8, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(7 * getWindowWidth() / 8, 7 * getWindowHeight() / 8, GLColor::blue);
EXPECT_PIXEL_RECT_EQ(4 * getWindowWidth() / 8, 0, getWindowWidth() / 4, getWindowHeight() / 2,
GLColor::white);
}
// Blit color to/from y-flipped with GL_MESA_framebuffer_flip_y framebuffers where dst framebuffer
// have different size.
TEST_P(BlitFramebufferANGLETest, BlitColorWithMesaYFlipSrcDst)
{
// OpenGL ES 3.0 / GL_NV_framebuffer_blit required for flip.
ANGLE_SKIP_TEST_IF(
(getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_NV_framebuffer_blit")) ||
!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
// Create a custom framebuffer as the default one cannot be flipped.
GLTexture tex0;
glBindTexture(GL_TEXTURE_2D, tex0);
const int fb0Width = getWindowWidth() / 2;
const int fb0Height = getWindowHeight() / 2;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fb0Width, fb0Height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
GLFramebuffer fb0;
glBindFramebuffer(GL_FRAMEBUFFER, fb0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f);
EXPECT_GL_NO_ERROR();
// Blit to default from y-flipped.
glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, fb0);
glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER_ANGLE, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
glFramebufferParameteriMESA(GL_READ_FRAMEBUFFER_ANGLE, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
const int fboTargetWidth = fb0Width / 2;
const int fboTargetHeight = fb0Height;
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, fboTargetWidth,
fboTargetHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), fb0Width / 2, 0, fb0Width,
fb0Height / 2, GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, fb0);
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 0);
// Left side have inverted checker pattern.
EXPECT_PIXEL_COLOR_EQ(fboTargetWidth / 4, fboTargetHeight / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(fboTargetWidth / 4, 3 * fboTargetHeight / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(3 * fboTargetWidth / 4, fboTargetHeight / 4, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(3 * fboTargetWidth / 4, 3 * fboTargetHeight / 4, GLColor::yellow);
// Right side is split to 2 parts where upper part have y-flipped checker pattern and the
// bottom one has white color.
EXPECT_PIXEL_COLOR_EQ(5 * fb0Width / 8, 5 * fb0Height / 8, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(5 * fb0Width / 8, 7 * fb0Height / 8, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(7 * fb0Width / 8, 5 * fb0Height / 8, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(7 * fb0Width / 8, 7 * fb0Height / 8, GLColor::yellow);
EXPECT_PIXEL_RECT_EQ(4 * fb0Width / 8, 0, fb0Width / 4, fb0Height / 2, GLColor::white);
}
// Same as BlitColorWithMesaYFlip but uses an integer buffer format.
TEST_P(BlitFramebufferANGLETest, BlitColorWithMesaYFlipInteger)
{
// OpenGL ES 3.0 / GL_NV_framebuffer_blit required for flip.
ANGLE_SKIP_TEST_IF(
(getClientMajorVersion() < 3 || !IsGLExtensionEnabled("GL_NV_framebuffer_blit")) ||
!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
GLTexture tex0;
glBindTexture(GL_TEXTURE_2D, tex0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8I, getWindowWidth(), getWindowHeight(), 0,
GL_RGBA_INTEGER, GL_BYTE, nullptr);
GLFramebuffer fb0;
glBindFramebuffer(GL_FRAMEBUFFER, fb0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex0, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
drawQuad(mCheckerProgram, essl1_shaders::PositionAttrib(), 0.8f);
EXPECT_GL_NO_ERROR();
GLTexture tex1;
glBindTexture(GL_TEXTURE_2D, tex1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8I, getWindowWidth(), getWindowHeight(), 0,
GL_RGBA_INTEGER, GL_BYTE, nullptr);
GLFramebuffer fb1;
glBindFramebuffer(GL_FRAMEBUFFER, fb1);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex1, 0);
// Blit to default from y-flipped.
glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fb0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, fb1);
const int fb1_target_width = getWindowHeight() / 3;
const int fb1_target_height = getWindowHeight() / 3;
glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, fb1_target_width,
fb1_target_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, fb1);
// The colors outside the target must remain the same.
EXPECT_PIXEL_8I(getWindowWidth() - 1, getWindowHeight() - 1, 0, 127, 127, 127);
EXPECT_PIXEL_8I(getWindowWidth() - 1, 0, 0, 127, 127, 127);
EXPECT_PIXEL_8I(0, getWindowHeight() - 1, 0, 127, 127, 127);
EXPECT_PIXEL_8I(fb1_target_width, fb1_target_height, 0, 127, 127, 127);
// While inside must change.
EXPECT_PIXEL_8I(fb1_target_width / 4, fb1_target_height / 4, 127, 0, 0, 127);
EXPECT_PIXEL_8I(fb1_target_width / 4, 3 * fb1_target_height / 4, 0, 127, 0, 127);
EXPECT_PIXEL_8I(3 * fb1_target_width / 4, fb1_target_height / 4, 0, 0, 127, 127);
EXPECT_PIXEL_8I(3 * fb1_target_width / 4, 3 * fb1_target_height / 4, 127, 127, 0, 127);
// Blit from y-flipped to default.
glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, fb1);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, fb0);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// Set y-flip flag so that y-flipped frame buffer blit to the original fbo in reverse. This
// should result in flipping y back.
glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER_ANGLE, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glBlitFramebuffer(0, 0, fb1_target_width, fb1_target_height, 0, 0, getWindowWidth(),
getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
// And explicitly disable y-flip so that read does not implicitly use this flag.
glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER_ANGLE, GL_FRAMEBUFFER_FLIP_Y_MESA, 0);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, fb0);
EXPECT_PIXEL_8I(getWindowWidth() / 4, getWindowHeight() / 4, 0, 127, 0, 127);
EXPECT_PIXEL_8I(getWindowWidth() / 4, 3 * getWindowHeight() / 4, 127, 0, 0, 127);
EXPECT_PIXEL_8I(3 * getWindowWidth() / 4, getWindowHeight() / 4, 127, 127, 0, 127);
EXPECT_PIXEL_8I(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, 0, 0, 127, 127);
}
// Draw to system framebuffer, blit whole-buffer color to user-created framebuffer. // Draw to system framebuffer, blit whole-buffer color to user-created framebuffer.
TEST_P(BlitFramebufferANGLETest, ReverseColorBlit) TEST_P(BlitFramebufferANGLETest, ReverseColorBlit)
{ {
@ -927,58 +1249,22 @@ TEST_P(BlitFramebufferANGLETest, BlitStencil)
// http://anglebug.com/5396 // http://anglebug.com/5396
ANGLE_SKIP_TEST_IF(IsAMD() && IsD3D9()); ANGLE_SKIP_TEST_IF(IsAMD() && IsD3D9());
glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); BlitStencilTestHelper(false /* mesaFlipY */);
}
glClearColor(0.0, 1.0, 0.0, 1.0); // Same as BlitStencil, but with y-flip flag set.
glClearStencil(0x0); TEST_P(BlitFramebufferANGLETest, BlitStencilWithMesaYFlip)
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); {
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ANGLE_framebuffer_blit") ||
!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
// Scissor half the screen so we fill the stencil only halfway // http://anglebug.com/2205
glScissor(0, 0, getWindowWidth(), getWindowHeight() / 2); ANGLE_SKIP_TEST_IF(IsIntel() && IsD3D9());
glEnable(GL_SCISSOR_TEST);
// fill the stencil buffer with 0x1 // http://anglebug.com/5396
glStencilFunc(GL_ALWAYS, 0x1, 0xFF); ANGLE_SKIP_TEST_IF(IsAMD() && IsD3D9());
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glEnable(GL_STENCIL_TEST);
drawQuad(mRedProgram, essl1_shaders::PositionAttrib(), 0.3f);
glDisable(GL_SCISSOR_TEST); BlitStencilTestHelper(true /* mesaFlipY */);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, mOriginalFBO);
glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, mUserFBO);
// These clears are not useful in theory because we're copying over them, but its
// helpful in debugging if we see white in any result.
glClearColor(1.0, 1.0, 1.0, 1.0);
glClearStencil(0x0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// depth blit request should be silently ignored, because the read FBO has no depth attachment
glBlitFramebufferANGLE(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(),
getWindowHeight(), GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
GL_NEAREST);
EXPECT_GL_NO_ERROR();
glBindFramebuffer(GL_FRAMEBUFFER, mOriginalFBO);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green);
glStencilFunc(GL_EQUAL, 0x1, 0xFF); // only pass if stencil buffer at pixel reads 0x1
drawQuad(mBlueProgram, essl1_shaders::PositionAttrib(),
0.8f); // blue quad will draw if stencil buffer was copied
glDisable(GL_STENCIL_TEST);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(3 * getWindowWidth() / 4, 3 * getWindowHeight() / 4, GLColor::green);
} }
// make sure that attempting to blit a partial depth buffer issues an error // make sure that attempting to blit a partial depth buffer issues an error
@ -1235,6 +1521,69 @@ class BlitFramebufferTest : public ANGLETest
glBindFramebuffer(GL_FRAMEBUFFER, *fbo); glBindFramebuffer(GL_FRAMEBUFFER, *fbo);
drawQuad(checkerProgram.get(), essl1_shaders::PositionAttrib(), 0.5f); drawQuad(checkerProgram.get(), essl1_shaders::PositionAttrib(), 0.5f);
} }
void BlitDepthStencilPixelByPixelTestHelper(bool mesaYFlip)
{
if (mesaYFlip)
ASSERT_TRUE(IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
glViewport(0, 0, 128, 1);
glEnable(GL_DEPTH_TEST);
GLFramebuffer srcFramebuffer;
GLRenderbuffer srcRenderbuffer;
glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer);
if (mesaYFlip)
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
glBindRenderbuffer(GL_RENDERBUFFER, srcRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 128, 1);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
srcRenderbuffer);
glClearDepthf(1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.0f, 0.5f);
glViewport(0, 0, 256, 2);
GLFramebuffer dstFramebuffer;
GLRenderbuffer dstRenderbuffer;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, dstRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 256, 2);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
dstRenderbuffer);
GLTexture dstColor;
glBindTexture(GL_TEXTURE_2D, dstColor);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 2);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstColor, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer);
glBlitFramebuffer(0, 0, 128, 1, 0, 0, 256, 2, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDepthMask(false);
glDepthFunc(GL_LESS);
drawQuad(drawRed, essl1_shaders::PositionAttrib(), -0.01f, 0.5f);
EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::red);
ANGLE_GL_PROGRAM(drawBlue, essl3_shaders::vs::Simple(), essl3_shaders::fs::Blue());
glEnable(GL_DEPTH_TEST);
glDepthMask(false);
glDepthFunc(GL_GREATER);
if (mesaYFlip)
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
drawQuad(drawBlue, essl1_shaders::PositionAttrib(), 0.01f, 0.5f);
if (mesaYFlip)
EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::green);
else
EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::blue);
}
}; };
class BlitFramebufferTestES31 : public BlitFramebufferTest class BlitFramebufferTestES31 : public BlitFramebufferTest
@ -2552,55 +2901,15 @@ TEST_P(BlitFramebufferTest, OOBWrite)
// Test blitting a depthStencil buffer with multiple depth values to a larger size. // Test blitting a depthStencil buffer with multiple depth values to a larger size.
TEST_P(BlitFramebufferTest, BlitDepthStencilPixelByPixel) TEST_P(BlitFramebufferTest, BlitDepthStencilPixelByPixel)
{ {
ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); BlitDepthStencilPixelByPixelTestHelper(false /* mesaYFlip */);
}
glViewport(0, 0, 128, 1); // Same as BlitDepthStencilPixelByPixel, but with y-flip flag set.
glEnable(GL_DEPTH_TEST); TEST_P(BlitFramebufferTest, BlitDepthStencilPixelByPixelMesaYFlip)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
GLFramebuffer srcFramebuffer; BlitDepthStencilPixelByPixelTestHelper(true /* mesaYFlip */);
GLRenderbuffer srcRenderbuffer;
glBindFramebuffer(GL_FRAMEBUFFER, srcFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, srcRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 128, 1);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
srcRenderbuffer);
glClearDepthf(1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.0f, 0.5f);
glViewport(0, 0, 256, 2);
GLFramebuffer dstFramebuffer;
GLRenderbuffer dstRenderbuffer;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, dstRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 256, 2);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
dstRenderbuffer);
GLTexture dstColor;
glBindTexture(GL_TEXTURE_2D, dstColor);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 2);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstColor, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFramebuffer);
glBlitFramebuffer(0, 0, 128, 1, 0, 0, 256, 2, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDepthMask(false);
glDepthFunc(GL_LESS);
drawQuad(drawRed, essl1_shaders::PositionAttrib(), -0.01f, 0.5f);
EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::red);
ANGLE_GL_PROGRAM(drawBlue, essl3_shaders::vs::Simple(), essl3_shaders::fs::Blue());
glEnable(GL_DEPTH_TEST);
glDepthMask(false);
glDepthFunc(GL_GREATER);
drawQuad(drawBlue, essl1_shaders::PositionAttrib(), 0.01f, 0.5f);
EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::blue);
} }
// Test that a draw call to a small FBO followed by a resolve of a large FBO works. // Test that a draw call to a small FBO followed by a resolve of a large FBO works.
@ -2718,6 +3027,227 @@ TEST_P(BlitFramebufferTestES31, BlitMultisampledRGBX8ToRGB8)
EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, 3 * kHeight / 4, GLColor::yellow); EXPECT_PIXEL_COLOR_EQ(3 * kWidth / 4, 3 * kHeight / 4, GLColor::yellow);
} }
// Test resolving a multisampled texture with blit. Draw flipped, resolve with read fbo flipped.
TEST_P(BlitFramebufferTestES31, MultisampleFlippedResolveReadWithBlitAndFlippedDraw)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
constexpr int kSize = 16;
glViewport(0, 0, kSize, kSize);
GLFramebuffer msaaFBO;
glBindFramebuffer(GL_FRAMEBUFFER, msaaFBO.get());
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
GLTexture texture;
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture.get());
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, false);
ASSERT_GL_NO_ERROR();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
texture.get(), 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(),
essl31_shaders::fs::RedGreenGradient());
drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR();
// Create another FBO to resolve the multisample buffer into.
GLTexture resolveTexture;
GLFramebuffer resolveFBO;
glBindTexture(GL_TEXTURE_2D, resolveTexture);
constexpr int kResolveFBOWidth = kSize - 3;
constexpr int kResolveFBOHeight = kSize - 2;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kResolveFBOWidth, kResolveFBOHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFBO);
glFramebufferParameteriMESA(GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO);
glBlitFramebuffer(0, 0, kResolveFBOWidth, kResolveFBOHeight, 0, 0, kResolveFBOWidth,
kResolveFBOHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO);
constexpr uint8_t kHalfPixelGradient = 256 / kSize / 2;
EXPECT_PIXEL_NEAR(0, 0, kHalfPixelGradient, kHalfPixelGradient, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, 0, 199, kHalfPixelGradient, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(0, kResolveFBOHeight - 1, kHalfPixelGradient, 215, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, kResolveFBOHeight - 1, 199, 215, 0, 255, 1.0);
}
// Test resolving a multisampled texture with blit. Draw non-flipped, resolve with read fbo flipped.
TEST_P(BlitFramebufferTestES31, MultisampleFlippedResolveReadWithBlitAndNonFlippedDraw)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
constexpr int kSize = 16;
glViewport(0, 0, kSize, kSize);
GLFramebuffer msaaFBO;
glBindFramebuffer(GL_FRAMEBUFFER, msaaFBO.get());
// Draw non-flipped - explicitly set y-flip to 0.
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 0);
GLTexture texture;
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture.get());
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, false);
ASSERT_GL_NO_ERROR();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
texture.get(), 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(),
essl31_shaders::fs::RedGreenGradient());
drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR();
// Create another FBO to resolve the multisample buffer into.
GLTexture resolveTexture;
GLFramebuffer resolveFBO;
glBindTexture(GL_TEXTURE_2D, resolveTexture);
constexpr int kResolveFBOWidth = kSize - 3;
constexpr int kResolveFBOHeight = kSize - 2;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kResolveFBOWidth, kResolveFBOHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFBO);
// Resolve with read fbo flipped and draw fbo non-flipped
glFramebufferParameteriMESA(GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO);
glBlitFramebuffer(0, 0, kResolveFBOWidth, kResolveFBOHeight, 0, 0, kResolveFBOWidth,
kResolveFBOHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO);
constexpr uint8_t kHalfPixelGradient = 256 / kSize / 2;
EXPECT_PIXEL_NEAR(0, 0, kHalfPixelGradient, 255 - kHalfPixelGradient, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, 0, 199, 255 - kHalfPixelGradient, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(0, kResolveFBOHeight - 1, kHalfPixelGradient, 40, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, kResolveFBOHeight - 1, 199, 40, 0, 255, 1.0);
}
// Test resolving a multisampled texture with blit. Draw non-flipped, resolve with draw fbo flipped
TEST_P(BlitFramebufferTestES31, MultisampleFlippedResolveDrawWithBlitAndNonFlippedDraw)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
constexpr int kSize = 16;
glViewport(0, 0, kSize, kSize);
GLFramebuffer msaaFBO;
glBindFramebuffer(GL_FRAMEBUFFER, msaaFBO.get());
// Draw non-flipped - explicitly set y-flip to 0.
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 0);
GLTexture texture;
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture.get());
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, false);
ASSERT_GL_NO_ERROR();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
texture.get(), 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(),
essl31_shaders::fs::RedGreenGradient());
drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR();
// Create another FBO to resolve the multisample buffer into.
GLTexture resolveTexture;
GLFramebuffer resolveFBO;
glBindTexture(GL_TEXTURE_2D, resolveTexture);
constexpr int kResolveFBOWidth = kSize - 3;
constexpr int kResolveFBOHeight = kSize - 2;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kResolveFBOWidth, kResolveFBOHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO);
// Resolve with draw fbo flipped and read fbo non-flipped.
glFramebufferParameteriMESA(GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 0);
glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
glBlitFramebuffer(0, 0, kResolveFBOWidth, kResolveFBOHeight, 0, 0, kResolveFBOWidth,
kResolveFBOHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO);
constexpr uint8_t kHalfPixelGradient = 256 / kSize / 2;
EXPECT_PIXEL_NEAR(0, 0, kHalfPixelGradient, kHalfPixelGradient, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, 0, 199, kHalfPixelGradient, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(0, kResolveFBOHeight - 1, kHalfPixelGradient, 215, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, kResolveFBOHeight - 1, 199, 215, 0, 255, 1.0);
}
// Test resolving a multisampled texture with blit. Draw non-flipped, resolve with both read and
// draw fbos flipped
TEST_P(BlitFramebufferTestES31, MultisampleFlippedResolveWithBlitAndNonFlippedDraw)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
constexpr int kSize = 16;
glViewport(0, 0, kSize, kSize);
GLFramebuffer msaaFBO;
glBindFramebuffer(GL_FRAMEBUFFER, msaaFBO.get());
// Draw non-flipped - explicitly set y-flip to 0.
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 0);
GLTexture texture;
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture.get());
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, false);
ASSERT_GL_NO_ERROR();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
texture.get(), 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(),
essl31_shaders::fs::RedGreenGradient());
drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR();
// Create another FBO to resolve the multisample buffer into.
GLTexture resolveTexture;
GLFramebuffer resolveFBO;
constexpr int kResolveFBOWidth = kSize - 3;
constexpr int kResolveFBOHeight = kSize - 2;
glBindTexture(GL_TEXTURE_2D, resolveTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kResolveFBOWidth, kResolveFBOHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, resolveFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolveTexture, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO);
// Resolve with draw and read fbo flipped.
glFramebufferParameteriMESA(GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
glFramebufferParameteriMESA(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
glBlitFramebuffer(0, 0, kResolveFBOWidth, kResolveFBOHeight, 0, 0, kResolveFBOWidth,
kResolveFBOHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
ASSERT_GL_NO_ERROR();
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFBO);
constexpr uint8_t kHalfPixelGradient = 256 / kSize / 2;
EXPECT_PIXEL_NEAR(0, 0, kHalfPixelGradient, 255 - kHalfPixelGradient, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, 0, 199, 255 - kHalfPixelGradient, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(0, kResolveFBOHeight - 1, kHalfPixelGradient, 40, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(kResolveFBOWidth - 1, kResolveFBOHeight - 1, 199, 40, 0, 255, 1.0);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BlitFramebufferANGLETest); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BlitFramebufferANGLETest);

Просмотреть файл

@ -90,6 +90,33 @@ class CopyTexImageTest : public ANGLETest
EXPECT_PIXEL_NEAR((xs + xe) / 2, (ys + ye) / 2, data[0], data[1], data[2], data[3], 1.0); EXPECT_PIXEL_NEAR((xs + xe) / 2, (ys + ye) / 2, data[0], data[1], data[2], data[3], 1.0);
} }
void verifyCheckeredResults(GLuint texture,
const GLubyte data0[4],
const GLubyte data1[4],
const GLubyte data2[4],
const GLubyte data3[4],
GLint fboWidth,
GLint fboHeight)
{
glViewport(0, 0, fboWidth, fboHeight);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Draw a quad with the target texture
glUseProgram(mTextureProgram);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(mTextureUniformLocation, 0);
drawQuad(mTextureProgram, essl1_shaders::PositionAttrib(), 0.5f);
// Expect that the rendered quad has the same color as the source texture
EXPECT_PIXEL_EQ(fboWidth / 4, fboHeight / 4, data0[0], data0[1], data0[2], data0[3]);
EXPECT_PIXEL_EQ(fboWidth / 4, 3 * fboHeight / 4, data1[0], data1[1], data1[2], data1[3]);
EXPECT_PIXEL_EQ(3 * fboWidth / 4, fboHeight / 4, data2[0], data2[1], data2[2], data2[3]);
EXPECT_PIXEL_EQ(3 * fboWidth / 4, 3 * fboHeight / 4, data3[0], data3[1], data3[2],
data3[3]);
}
void runCopyTexImageTest(GLenum format, GLubyte expected[3][4]) void runCopyTexImageTest(GLenum format, GLubyte expected[3][4])
{ {
GLTexture tex; GLTexture tex;
@ -116,6 +143,47 @@ class CopyTexImageTest : public ANGLETest
} }
} }
// x, y, width, height specify the portion of fbo to be copied into tex.
// flip_y specifies if the glCopyTextImage must be done from y-flipped fbo.
void runCopyTexImageTestCheckered(GLenum format,
const uint32_t x[3],
const uint32_t y[3],
const uint32_t width[3],
const uint32_t height[3],
const GLubyte expectedData0[4],
const GLubyte expectedData1[4],
const GLubyte expectedData2[4],
const GLubyte expectedData3[4],
bool mesaFlipY)
{
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
// Disable mipmapping
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Perform the copy multiple times.
for (size_t i = 0; i < kFboCount; ++i)
{
glViewport(0, 0, kFboSizes[i], kFboSizes[i]);
glBindFramebuffer(GL_FRAMEBUFFER, mFbos[i]);
ANGLE_GL_PROGRAM(checkerProgram, essl1_shaders::vs::Passthrough(),
essl1_shaders::fs::Checkered());
drawQuad(checkerProgram.get(), essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_GL_NO_ERROR();
if (mesaFlipY)
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x[i], y[i], width[i], height[i], 0);
ASSERT_GL_NO_ERROR();
verifyCheckeredResults(tex, expectedData0, expectedData1, expectedData2, expectedData3,
kFboSizes[i], kFboSizes[i]);
}
}
void runCopyTexSubImageTest(GLenum format, GLubyte expected[3][4]) void runCopyTexSubImageTest(GLenum format, GLubyte expected[3][4])
{ {
GLTexture tex; GLTexture tex;
@ -566,6 +634,107 @@ TEST_P(CopyTexImageTest, CopyTexSubImageFrom3DTexureOES)
} }
} }
// Tests image copy from y-flipped fbo works.
TEST_P(CopyTexImageTest, CopyTexImageMesaYFlip)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
std::array<uint32_t, 3> copyOrigin{0};
std::array<uint32_t, 3> copySize;
for (size_t i = 0; i < kFboCount; i++)
copySize[i] = kFboSizes[i];
initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
runCopyTexImageTestCheckered(GL_RGBA, copyOrigin.data(), copyOrigin.data(), copySize.data(),
copySize.data(), GLColor::green.data(), GLColor::red.data(),
GLColor::yellow.data(), GLColor::blue.data(),
true /* mesaFlipY */);
}
// Tests image partial copy from y-flipped fbo works.
TEST_P(CopyTexImageTest, CopyTexImageMesaYFlipPartial)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
std::array<uint32_t, kFboCount> copyX;
std::array<uint32_t, kFboCount> copyY{0};
std::array<uint32_t, kFboCount> copyWidth;
std::array<uint32_t, kFboCount> copyHeight;
for (size_t i = 0; i < kFboCount; i++)
{
copyX[i] = kFboSizes[i] / 2;
copyHeight[i] = kFboSizes[i];
}
copyWidth = copyX;
initializeResources(GL_RGBA, GL_UNSIGNED_BYTE);
runCopyTexImageTestCheckered(GL_RGBA, copyX.data(), copyY.data(), copyWidth.data(),
copyHeight.data(), GLColor::yellow.data(), GLColor::blue.data(),
GLColor::yellow.data(), GLColor::blue.data(),
true /* mesaFlipY */);
}
// Tests subimage copy from y-flipped fbo works.
TEST_P(CopyTexImageTest, CopyTexSubImageMesaYFlip)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
GLuint format = GL_RGBA;
initializeResources(format, GL_UNSIGNED_BYTE);
glViewport(0, 0, kFboSizes[0], kFboSizes[0]);
glBindFramebuffer(GL_FRAMEBUFFER, mFbos[0]);
ANGLE_GL_PROGRAM(checkerProgram, essl1_shaders::vs::Passthrough(),
essl1_shaders::fs::Checkered());
drawQuad(checkerProgram.get(), essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_GL_NO_ERROR();
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
// Disable mipmapping
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Create the texture with copy of the first fbo.
glBindFramebuffer(GL_FRAMEBUFFER, mFbos[0]);
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
glCopyTexImage2D(GL_TEXTURE_2D, 0, format, 0, 0, kFboSizes[0], kFboSizes[0], 0);
ASSERT_GL_NO_ERROR();
// Make sure out-of-bound writes to the texture return invalid value.
glBindFramebuffer(GL_FRAMEBUFFER, mFbos[1]);
drawQuad(checkerProgram.get(), essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_GL_NO_ERROR();
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
// xoffset < 0 and yoffset < 0
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, -1, -1, 0, 0, kFboSizes[0], kFboSizes[0]);
ASSERT_GL_ERROR(GL_INVALID_VALUE);
// xoffset + width > w and yoffset + height > h
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 1, 1, 0, 0, kFboSizes[0], kFboSizes[0]);
ASSERT_GL_ERROR(GL_INVALID_VALUE);
// xoffset + width > w and yoffset + height > h, out of bounds
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, -1, -1, 1 + kFboSizes[0], 1 + kFboSizes[0]);
ASSERT_GL_ERROR(GL_INVALID_VALUE);
// Copy the second fbo over a portion of the image.
GLint offset = kFboSizes[0] / 2;
GLint extent = kFboSizes[0] - offset;
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, offset, offset, kFboSizes[1] / 2, kFboSizes[1] / 2,
extent, extent);
ASSERT_GL_NO_ERROR();
// Only part of the image is changed.
verifyCheckeredResults(tex, GLColor::green.data(), GLColor::red.data(), GLColor::yellow.data(),
GLColor::blue.data(), kFboSizes[0], kFboSizes[0]);
}
// specialization of CopyTexImageTest is added so that some tests can be explicitly run with an ES3 // specialization of CopyTexImageTest is added so that some tests can be explicitly run with an ES3
// context // context
class CopyTexImageTestES3 : public CopyTexImageTest class CopyTexImageTestES3 : public CopyTexImageTest

Просмотреть файл

@ -115,7 +115,7 @@ class CopyTextureTest : public ANGLETest
}; };
using CopyTextureVariationsTestParams = using CopyTextureVariationsTestParams =
std::tuple<angle::PlatformParameters, GLenum, GLenum, bool, bool, bool>; std::tuple<angle::PlatformParameters, GLenum, GLenum, bool, bool, bool, GLint>;
std::string CopyTextureVariationsTestPrint( std::string CopyTextureVariationsTestPrint(
const ::testing::TestParamInfo<CopyTextureVariationsTestParams> &paramsInfo) const ::testing::TestParamInfo<CopyTextureVariationsTestParams> &paramsInfo)
@ -184,6 +184,10 @@ std::string CopyTextureVariationsTestPrint(
{ {
out << "UnmultiplyAlpha"; out << "UnmultiplyAlpha";
} }
if (std::get<6>(params))
{
out << "MesaYFlip";
}
return out.str(); return out.str();
} }
@ -422,13 +426,18 @@ class CopyTextureVariationsTest : public ANGLETestWithParam<CopyTextureVariation
GLenum destFormat, GLenum destFormat,
bool flipY, bool flipY,
bool premultiplyAlpha, bool premultiplyAlpha,
bool unmultiplyAlpha) bool unmultiplyAlpha,
GLint mesaYFlipParam)
{ {
if (!checkExtensions(sourceFormat, destFormat)) if (!checkExtensions(sourceFormat, destFormat))
{ {
return; return;
} }
const bool hasMesaFbFlipYExt = IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y");
if (mesaYFlipParam && !hasMesaFbFlipYExt)
ASSERT_TRUE(hasMesaFbFlipYExt);
if (sourceFormat == GL_LUMINANCE || sourceFormat == GL_LUMINANCE_ALPHA || if (sourceFormat == GL_LUMINANCE || sourceFormat == GL_LUMINANCE_ALPHA ||
sourceFormat == GL_ALPHA || destFormat == GL_LUMINANCE || sourceFormat == GL_ALPHA || destFormat == GL_LUMINANCE ||
destFormat == GL_LUMINANCE_ALPHA || destFormat == GL_ALPHA) destFormat == GL_LUMINANCE_ALPHA || destFormat == GL_ALPHA)
@ -457,6 +466,11 @@ class CopyTextureVariationsTest : public ANGLETestWithParam<CopyTextureVariation
initializeSourceTexture(sourceTarget, sourceFormat, &srcColors[i * componentCount], initializeSourceTexture(sourceTarget, sourceFormat, &srcColors[i * componentCount],
componentCount); componentCount);
if (hasMesaFbFlipYExt)
{
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA,
mesaYFlipParam);
}
glCopyTextureCHROMIUM(mTextures[0], 0, GL_TEXTURE_2D, mTextures[1], 0, destFormat, glCopyTextureCHROMIUM(mTextures[0], 0, GL_TEXTURE_2D, mTextures[1], 0, destFormat,
GL_UNSIGNED_BYTE, flipY, premultiplyAlpha, unmultiplyAlpha); GL_UNSIGNED_BYTE, flipY, premultiplyAlpha, unmultiplyAlpha);
@ -467,17 +481,37 @@ class CopyTextureVariationsTest : public ANGLETestWithParam<CopyTextureVariation
if (flipY) if (flipY)
{ {
EXPECT_PIXEL_COLOR_NEAR(0, 0, destColors[i + 2], 1.0); if (mesaYFlipParam)
EXPECT_PIXEL_COLOR_NEAR(1, 0, destColors[i + 3], 1.0); {
EXPECT_PIXEL_COLOR_NEAR(0, 1, destColors[i + 0], 1.0); EXPECT_PIXEL_COLOR_NEAR(0, 0, destColors[i + 0], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 1, destColors[i + 1], 1.0); EXPECT_PIXEL_COLOR_NEAR(1, 0, destColors[i + 1], 1.0);
EXPECT_PIXEL_COLOR_NEAR(0, 1, destColors[i + 2], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 1, destColors[i + 3], 1.0);
}
else
{
EXPECT_PIXEL_COLOR_NEAR(0, 0, destColors[i + 2], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 0, destColors[i + 3], 1.0);
EXPECT_PIXEL_COLOR_NEAR(0, 1, destColors[i + 0], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 1, destColors[i + 1], 1.0);
}
} }
else else
{ {
EXPECT_PIXEL_COLOR_NEAR(0, 0, destColors[i + 0], 1.0); if (mesaYFlipParam)
EXPECT_PIXEL_COLOR_NEAR(1, 0, destColors[i + 1], 1.0); {
EXPECT_PIXEL_COLOR_NEAR(0, 1, destColors[i + 2], 1.0); EXPECT_PIXEL_COLOR_NEAR(0, 0, destColors[i + 2], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 1, destColors[i + 3], 1.0); EXPECT_PIXEL_COLOR_NEAR(1, 0, destColors[i + 3], 1.0);
EXPECT_PIXEL_COLOR_NEAR(0, 1, destColors[i + 0], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 1, destColors[i + 1], 1.0);
}
else
{
EXPECT_PIXEL_COLOR_NEAR(0, 0, destColors[i + 0], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 0, destColors[i + 1], 1.0);
EXPECT_PIXEL_COLOR_NEAR(0, 1, destColors[i + 2], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 1, destColors[i + 3], 1.0);
}
} }
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
@ -489,13 +523,18 @@ class CopyTextureVariationsTest : public ANGLETestWithParam<CopyTextureVariation
GLenum destFormat, GLenum destFormat,
bool flipY, bool flipY,
bool premultiplyAlpha, bool premultiplyAlpha,
bool unmultiplyAlpha) bool unmultiplyAlpha,
GLint mesaYFlipParam)
{ {
if (!checkExtensions(sourceFormat, destFormat)) if (!checkExtensions(sourceFormat, destFormat))
{ {
return; return;
} }
const bool hasMesaFbFlipYExt = IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y");
if (mesaYFlipParam && !hasMesaFbFlipYExt)
ASSERT_TRUE(hasMesaFbFlipYExt);
if (sourceFormat == GL_LUMINANCE || sourceFormat == GL_LUMINANCE_ALPHA || if (sourceFormat == GL_LUMINANCE || sourceFormat == GL_LUMINANCE_ALPHA ||
sourceFormat == GL_ALPHA || destFormat == GL_LUMINANCE || sourceFormat == GL_ALPHA || destFormat == GL_LUMINANCE ||
destFormat == GL_LUMINANCE_ALPHA || destFormat == GL_ALPHA) destFormat == GL_LUMINANCE_ALPHA || destFormat == GL_ALPHA)
@ -528,6 +567,11 @@ class CopyTextureVariationsTest : public ANGLETestWithParam<CopyTextureVariation
glTexImage2D(GL_TEXTURE_2D, 0, destFormat, 2, 2, 0, destFormat, GL_UNSIGNED_BYTE, glTexImage2D(GL_TEXTURE_2D, 0, destFormat, 2, 2, 0, destFormat, GL_UNSIGNED_BYTE,
nullptr); nullptr);
if (hasMesaFbFlipYExt)
{
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA,
mesaYFlipParam);
}
glCopySubTextureCHROMIUM(mTextures[0], 0, GL_TEXTURE_2D, mTextures[1], 0, 0, 0, 0, 0, 2, glCopySubTextureCHROMIUM(mTextures[0], 0, GL_TEXTURE_2D, mTextures[1], 0, 0, 0, 0, 0, 2,
2, flipY, premultiplyAlpha, unmultiplyAlpha); 2, flipY, premultiplyAlpha, unmultiplyAlpha);
@ -542,17 +586,37 @@ class CopyTextureVariationsTest : public ANGLETestWithParam<CopyTextureVariation
if (flipY) if (flipY)
{ {
EXPECT_PIXEL_COLOR_NEAR(0, 0, destColors[i + 2], 1.0); if (mesaYFlipParam)
EXPECT_PIXEL_COLOR_NEAR(1, 0, destColors[i + 3], 1.0); {
EXPECT_PIXEL_COLOR_NEAR(0, 1, destColors[i + 0], 1.0); EXPECT_PIXEL_COLOR_NEAR(0, 0, destColors[i + 0], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 1, destColors[i + 1], 1.0); EXPECT_PIXEL_COLOR_NEAR(1, 0, destColors[i + 1], 1.0);
EXPECT_PIXEL_COLOR_NEAR(0, 1, destColors[i + 2], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 1, destColors[i + 3], 1.0);
}
else
{
EXPECT_PIXEL_COLOR_NEAR(0, 0, destColors[i + 2], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 0, destColors[i + 3], 1.0);
EXPECT_PIXEL_COLOR_NEAR(0, 1, destColors[i + 0], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 1, destColors[i + 1], 1.0);
}
} }
else else
{ {
EXPECT_PIXEL_COLOR_NEAR(0, 0, destColors[i + 0], 1.0); if (mesaYFlipParam)
EXPECT_PIXEL_COLOR_NEAR(1, 0, destColors[i + 1], 1.0); {
EXPECT_PIXEL_COLOR_NEAR(0, 1, destColors[i + 2], 1.0); EXPECT_PIXEL_COLOR_NEAR(0, 0, destColors[i + 2], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 1, destColors[i + 3], 1.0); EXPECT_PIXEL_COLOR_NEAR(1, 0, destColors[i + 3], 1.0);
EXPECT_PIXEL_COLOR_NEAR(0, 1, destColors[i + 0], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 1, destColors[i + 1], 1.0);
}
else
{
EXPECT_PIXEL_COLOR_NEAR(0, 0, destColors[i + 0], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 0, destColors[i + 1], 1.0);
EXPECT_PIXEL_COLOR_NEAR(0, 1, destColors[i + 2], 1.0);
EXPECT_PIXEL_COLOR_NEAR(1, 1, destColors[i + 3], 1.0);
}
} }
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
@ -904,6 +968,7 @@ constexpr GLenum kCopyTextureVariationsSrcFormats[] = {
GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_BGRA_EXT}; GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_BGRA_EXT};
constexpr GLenum kCopyTextureVariationsDstFormats[] = {GL_RGB, GL_RGBA, GL_BGRA_EXT, constexpr GLenum kCopyTextureVariationsDstFormats[] = {GL_RGB, GL_RGBA, GL_BGRA_EXT,
GL_SRGB_ALPHA_EXT}; GL_SRGB_ALPHA_EXT};
constexpr GLint kMesaYFlips[] = {0, 1};
} // anonymous namespace } // anonymous namespace
TEST_P(CopyTextureVariationsTest, CopyTexture) TEST_P(CopyTextureVariationsTest, CopyTexture)
@ -917,32 +982,57 @@ TEST_P(CopyTextureVariationsTest, CopyTexture)
ANGLE_SKIP_TEST_IF(IsWindows7() && IsNVIDIA() && IsOpenGLES()); ANGLE_SKIP_TEST_IF(IsWindows7() && IsNVIDIA() && IsOpenGLES());
} }
if (std::get<6>(GetParam()))
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
}
testCopyTexture(GL_TEXTURE_2D, std::get<1>(GetParam()), std::get<2>(GetParam()), testCopyTexture(GL_TEXTURE_2D, std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()), std::get<4>(GetParam()), std::get<5>(GetParam())); std::get<3>(GetParam()), std::get<4>(GetParam()), std::get<5>(GetParam()),
std::get<6>(GetParam()));
} }
TEST_P(CopyTextureVariationsTest, CopySubTexture) TEST_P(CopyTextureVariationsTest, CopySubTexture)
{ {
// http://anglebug.com/5723 // http://anglebug.com/5723
ANGLE_SKIP_TEST_IF(IsOzone()); ANGLE_SKIP_TEST_IF(IsOzone());
if (std::get<6>(GetParam()))
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
}
testCopySubTexture(GL_TEXTURE_2D, std::get<1>(GetParam()), std::get<2>(GetParam()), testCopySubTexture(GL_TEXTURE_2D, std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()), std::get<4>(GetParam()), std::get<5>(GetParam())); std::get<3>(GetParam()), std::get<4>(GetParam()), std::get<5>(GetParam()),
std::get<6>(GetParam()));
} }
TEST_P(CopyTextureVariationsTest, CopyTextureRectangle) TEST_P(CopyTextureVariationsTest, CopyTextureRectangle)
{ {
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_texture_rectangle")); ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_texture_rectangle"));
if (std::get<6>(GetParam()))
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
}
testCopyTexture(GL_TEXTURE_RECTANGLE_ANGLE, std::get<1>(GetParam()), std::get<2>(GetParam()), testCopyTexture(GL_TEXTURE_RECTANGLE_ANGLE, std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()), std::get<4>(GetParam()), std::get<5>(GetParam())); std::get<3>(GetParam()), std::get<4>(GetParam()), std::get<5>(GetParam()),
std::get<6>(GetParam()));
} }
TEST_P(CopyTextureVariationsTest, CopySubTextureRectangle) TEST_P(CopyTextureVariationsTest, CopySubTextureRectangle)
{ {
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_texture_rectangle")); ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_texture_rectangle"));
if (std::get<6>(GetParam()))
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
}
testCopySubTexture(GL_TEXTURE_RECTANGLE_ANGLE, std::get<1>(GetParam()), std::get<2>(GetParam()), testCopySubTexture(GL_TEXTURE_RECTANGLE_ANGLE, std::get<1>(GetParam()), std::get<2>(GetParam()),
std::get<3>(GetParam()), std::get<4>(GetParam()), std::get<5>(GetParam())); std::get<3>(GetParam()), std::get<4>(GetParam()), std::get<5>(GetParam()),
std::get<6>(GetParam()));
} }
// Test that copying to cube maps works // Test that copying to cube maps works
@ -2534,13 +2624,14 @@ TEST_P(CopyTextureTestES3, InvalidateBlitThenBlend1000Layers)
#endif #endif
ANGLE_INSTANTIATE_TEST_ES2(CopyTextureTest); ANGLE_INSTANTIATE_TEST_ES2(CopyTextureTest);
ANGLE_INSTANTIATE_TEST_COMBINE_5(CopyTextureVariationsTest, ANGLE_INSTANTIATE_TEST_COMBINE_6(CopyTextureVariationsTest,
CopyTextureVariationsTestPrint, CopyTextureVariationsTestPrint,
testing::ValuesIn(kCopyTextureVariationsSrcFormats), testing::ValuesIn(kCopyTextureVariationsSrcFormats),
testing::ValuesIn(kCopyTextureVariationsDstFormats), testing::ValuesIn(kCopyTextureVariationsDstFormats),
testing::Bool(), // flipY testing::Bool(), // flipY
testing::Bool(), // premultiplyAlpha testing::Bool(), // premultiplyAlpha
testing::Bool(), // unmultiplyAlpha testing::Bool(), // unmultiplyAlpha
testing::ValuesIn(kMesaYFlips),
ES2_D3D9(), ES2_D3D9(),
ES2_D3D11(), ES2_D3D11(),
ES2_OPENGL(), ES2_OPENGL(),

Просмотреть файл

@ -1863,6 +1863,43 @@ TEST_P(FramebufferTest_ES31, IncompleteMultisampleFixedSampleLocationsTex)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
// Tests that draw to Y-flipped FBO results in correct pixels.
TEST_P(FramebufferTest_ES31, BasicDrawToYFlippedFBO)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_MESA_framebuffer_flip_y"));
constexpr int kSize = 16;
glViewport(0, 0, kSize, kSize);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 1);
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture.get());
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize);
ASSERT_GL_NO_ERROR();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(),
essl31_shaders::fs::RedGreenGradient());
drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR();
// Remove the flag so that glReadPixels do not implicitly use that.
glFramebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA, 0);
constexpr uint8_t kHalfPixelGradient = 256 / kSize / 2;
EXPECT_PIXEL_NEAR(0, 0, kHalfPixelGradient, 255 - kHalfPixelGradient, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(kSize - 1, 0, 255 - kHalfPixelGradient, 255 - kHalfPixelGradient, 0, 255,
1.0);
EXPECT_PIXEL_NEAR(0, kSize - 1, kHalfPixelGradient, kHalfPixelGradient, 0, 255, 1.0);
EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 255 - kHalfPixelGradient, kHalfPixelGradient, 0, 255,
1.0);
}
// Test resolving a multisampled texture with blit // Test resolving a multisampled texture with blit
TEST_P(FramebufferTest_ES31, MultisampleResolveWithBlit) TEST_P(FramebufferTest_ES31, MultisampleResolveWithBlit)
{ {

Просмотреть файл

@ -256,6 +256,14 @@ struct CombinedPrintToStringParamName
testing::Combine(ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), \ testing::Combine(ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), \
combine1, combine2, combine3, combine4, combine5), \ combine1, combine2, combine3, combine4, combine5), \
print) print)
#define ANGLE_INSTANTIATE_TEST_COMBINE_6(testName, print, combine1, combine2, combine3, combine4, \
combine5, combine6, first, ...) \
const decltype(first) testName##params[] = {first, ##__VA_ARGS__}; \
INSTANTIATE_TEST_SUITE_P( \
, testName, \
testing::Combine(ANGLE_INSTANTIATE_TEST_PLATFORMS(testName), combine1, combine2, combine3, \
combine4, combine5, combine6), \
print)
// Checks if a config is expected to be supported by checking a system-based allow list. // Checks if a config is expected to be supported by checking a system-based allow list.
bool IsConfigAllowlisted(const SystemInfo &systemInfo, const PlatformParameters &param); bool IsConfigAllowlisted(const SystemInfo &systemInfo, const PlatformParameters &param);