// // Copyright 2020 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. // // EGLPreRotationTest: // Tests pertaining to Android pre-rotation. // #include #include #include "common/Color.h" #include "common/platform.h" #include "test_utils/ANGLETest.h" #include "test_utils/gl_raii.h" #include "util/EGLWindow.h" #include "util/OSWindow.h" #include "util/Timer.h" #include "util/test_utils.h" using namespace angle; namespace { using EGLPreRotationSurfaceTestParams = std::tuple; std::string PrintToStringParamName( const ::testing::TestParamInfo &info) { std::stringstream ss; ss << std::get<0>(info.param); if (std::get<1>(info.param)) { ss << "__PreRotationEnabled"; } else { ss << "__PreRotationDisabled"; } return ss.str(); } // A class to test various Android pre-rotation cases. In order to make it easier to debug test // failures, the initial window size is 256x256, and each pixel will have a unique and predictable // value. The red channel will increment with the x axis, and the green channel will increment // with the y axis. The four corners will have the following values: // // Where GLES Render & ReadPixels coords Color (in Hex) // Lower-left, which is (-1.0,-1.0) & ( 0, 0) in GLES will be black (0x00, 0x00, 0x00, 0xFF) // Lower-right, which is ( 1.0,-1.0) & (256, 0) in GLES will be red (0xFF, 0x00, 0x00, 0xFF) // Upper-left, which is (-1.0, 1.0) & ( 0, 256) in GLES will be green (0x00, 0xFF, 0x00, 0xFF) // Upper-right, which is ( 1.0, 1.0) & (256, 256) in GLES will be yellow (0xFF, 0xFF, 0x00, 0xFF) class EGLPreRotationSurfaceTest : public ANGLETestWithParam { protected: EGLPreRotationSurfaceTest() : mDisplay(EGL_NO_DISPLAY), mWindowSurface(EGL_NO_SURFACE), mContext(EGL_NO_CONTEXT), mOSWindow(nullptr), mSize(256) {} // Release any resources created in the test body void testTearDown() override { if (mDisplay != EGL_NO_DISPLAY) { eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (mWindowSurface != EGL_NO_SURFACE) { eglDestroySurface(mDisplay, mWindowSurface); mWindowSurface = EGL_NO_SURFACE; } if (mContext != EGL_NO_CONTEXT) { eglDestroyContext(mDisplay, mContext); mContext = EGL_NO_CONTEXT; } eglTerminate(mDisplay); mDisplay = EGL_NO_DISPLAY; } mOSWindow->destroy(); OSWindow::Delete(&mOSWindow); ASSERT_TRUE(mWindowSurface == EGL_NO_SURFACE && mContext == EGL_NO_CONTEXT); } void testSetUp() override { mOSWindow = OSWindow::New(); mOSWindow->initialize("EGLSurfaceTest", mSize, mSize); } void initializeDisplay() { const angle::PlatformParameters platform = ::testing::get<0>(GetParam()); GLenum platformType = platform.getRenderer(); GLenum deviceType = platform.getDeviceType(); std::vector enabledFeatures; std::vector disabledFeatures; if (::testing::get<1>(GetParam())) { enabledFeatures.push_back("enablePreRotateSurfaces"); } else { disabledFeatures.push_back("enablePreRotateSurfaces"); } enabledFeatures.push_back(nullptr); disabledFeatures.push_back(nullptr); std::vector displayAttributes; displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE); displayAttributes.push_back(platformType); displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE); displayAttributes.push_back(EGL_DONT_CARE); displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE); displayAttributes.push_back(EGL_DONT_CARE); displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE); displayAttributes.push_back(deviceType); displayAttributes.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE); displayAttributes.push_back(reinterpret_cast(enabledFeatures.data())); displayAttributes.push_back(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE); displayAttributes.push_back(reinterpret_cast(disabledFeatures.data())); displayAttributes.push_back(EGL_NONE); mDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast(mOSWindow->getNativeDisplay()), displayAttributes.data()); ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY); EGLint majorVersion, minorVersion; ASSERT_TRUE(eglInitialize(mDisplay, &majorVersion, &minorVersion) == EGL_TRUE); eglBindAPI(EGL_OPENGL_ES_API); ASSERT_EGL_SUCCESS(); } void initializeContext() { EGLint contextAttibutes[] = {EGL_CONTEXT_CLIENT_VERSION, ::testing::get<0>(GetParam()).majorVersion, EGL_NONE}; mContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes); ASSERT_EGL_SUCCESS(); } void initializeSurfaceWithRGBA8888Config() { const EGLint configAttributes[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE}; EGLint configCount; EGLConfig config; ASSERT_TRUE(eglChooseConfig(mDisplay, configAttributes, &config, 1, &configCount) || (configCount != 1) == EGL_TRUE); mConfig = config; EGLint surfaceType = EGL_NONE; eglGetConfigAttrib(mDisplay, mConfig, EGL_SURFACE_TYPE, &surfaceType); std::vector windowAttributes; windowAttributes.push_back(EGL_NONE); if (surfaceType & EGL_WINDOW_BIT) { // Create first window surface mWindowSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), windowAttributes.data()); ASSERT_EGL_SUCCESS(); } initializeContext(); } void initializeSurfaceWithRGBA8888d24s8Config() { const EGLint configAttributes[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_STENCIL_SIZE, 8, EGL_SAMPLE_BUFFERS, 0, EGL_NONE}; EGLint configCount; EGLConfig config; ASSERT_TRUE(eglChooseConfig(mDisplay, configAttributes, &config, 1, &configCount) || (configCount != 1) == EGL_TRUE); mConfig = config; EGLint surfaceType = EGL_NONE; eglGetConfigAttrib(mDisplay, mConfig, EGL_SURFACE_TYPE, &surfaceType); std::vector windowAttributes; windowAttributes.push_back(EGL_NONE); if (surfaceType & EGL_WINDOW_BIT) { // Create first window surface mWindowSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), windowAttributes.data()); ASSERT_EGL_SUCCESS(); } initializeContext(); } void testDrawingAndReadPixels() { glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); EXPECT_PIXEL_COLOR_EQ(0, mSize - 1, GLColor::green); EXPECT_PIXEL_COLOR_EQ(mSize - 1, 0, GLColor::red); EXPECT_PIXEL_COLOR_EQ(mSize - 1, mSize - 1, GLColor::yellow); ASSERT_GL_NO_ERROR(); eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_EGL_SUCCESS(); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); EXPECT_PIXEL_COLOR_EQ(0, mSize - 1, GLColor::green); EXPECT_PIXEL_COLOR_EQ(mSize - 1, 0, GLColor::red); EXPECT_PIXEL_COLOR_EQ(mSize - 1, mSize - 1, GLColor::yellow); ASSERT_GL_NO_ERROR(); { // Now, test a 4x4 area in the center of the window, which should tell us if a non-1x1 // ReadPixels is oriented correctly for the device's orientation: GLint xOffset = 126; GLint yOffset = 126; GLsizei width = 4; GLsizei height = 4; std::vector pixels(width * height); glReadPixels(xOffset, yOffset, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]); EXPECT_GL_NO_ERROR(); // Expect that all red values equate to x and green values equate to y for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int index = (y * width) + x; GLColor expectedPixel(xOffset + x, yOffset + y, 0, 255); GLColor actualPixel = pixels[index]; EXPECT_EQ(expectedPixel, actualPixel); } } } { // Now, test a 8x4 area off-the-center of the window, just to make sure that works too: GLint xOffset = 13; GLint yOffset = 26; GLsizei width = 8; GLsizei height = 4; std::vector pixels2(width * height); glReadPixels(xOffset, yOffset, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels2[0]); EXPECT_GL_NO_ERROR(); // Expect that all red values equate to x and green values equate to y for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int index = (y * width) + x; GLColor expectedPixel(xOffset + x, yOffset + y, 0, 255); GLColor actualPixel = pixels2[index]; EXPECT_EQ(expectedPixel, actualPixel); } } } eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_EGL_SUCCESS(); } EGLDisplay mDisplay; EGLSurface mWindowSurface; EGLContext mContext; EGLConfig mConfig; OSWindow *mOSWindow; int mSize; }; // Provide a predictable pattern for testing pre-rotation TEST_P(EGLPreRotationSurfaceTest, OrientedWindowWithDraw) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); // Init program constexpr char kVS[] = "attribute vec2 position;\n" "attribute vec2 redGreen;\n" "varying vec2 v_data;\n" "void main() {\n" " gl_Position = vec4(position, 0, 1);\n" " v_data = redGreen;\n" "}"; constexpr char kFS[] = "varying highp vec2 v_data;\n" "void main() {\n" " gl_FragColor = vec4(v_data, 0, 1);\n" "}"; ANGLE_GL_PROGRAM(program, kVS, kFS); glUseProgram(program); GLint positionLocation = glGetAttribLocation(program, "position"); ASSERT_NE(-1, positionLocation); GLint redGreenLocation = glGetAttribLocation(program, "redGreen"); ASSERT_NE(-1, redGreenLocation); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffers[2]; glBindVertexArray(vertexArray); std::vector indices = {0, 1, 2, 2, 3, 0}; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indices.size(), &indices[0], GL_STATIC_DRAW); std::vector positionData = {// quad vertices -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f}; glBindBuffer(GL_ARRAY_BUFFER, vertexBuffers[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0], GL_STATIC_DRAW); glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr); glEnableVertexAttribArray(positionLocation); std::vector redGreenData = {// green(0,1), black(0,0), red(1,0), yellow(1,1) 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f}; glBindBuffer(GL_ARRAY_BUFFER, vertexBuffers[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * redGreenData.size(), &redGreenData[0], GL_STATIC_DRAW); glVertexAttribPointer(redGreenLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr); glEnableVertexAttribArray(redGreenLocation); ASSERT_GL_NO_ERROR(); testDrawingAndReadPixels(); } // Use dFdx() and dFdy() and still provide a predictable pattern for testing pre-rotation // In this case, the color values will be the following: (dFdx(v_data.x), dFdy(v_data.y), 0, 1). // To help make this meaningful for pre-rotation, the derivatives will vary in the four corners of // the window: // // +------------+------------+ +--------+--------+ // | ( 0, 219) | (239, 249) | | Green | Yellow | // +------------+------------+ OR +--------+--------+ // | ( 0, 0) | (229, 0) | | Black | Red | // +------------+------------+ +--------+--------+ TEST_P(EGLPreRotationSurfaceTest, OrientedWindowWithDerivativeDraw) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); // Init program constexpr char kVS[] = "#version 300 es\n" "in highp vec2 position;\n" "in highp vec2 redGreen;\n" "out highp vec2 v_data;\n" "void main() {\n" " gl_Position = vec4(position, 0, 1);\n" " v_data = redGreen;\n" "}"; constexpr char kFS[] = "#version 300 es\n" "in highp vec2 v_data;\n" "out highp vec4 FragColor;\n" "void main() {\n" " FragColor = vec4(dFdx(v_data.x), dFdy(v_data.y), 0, 1);\n" "}"; ANGLE_GL_PROGRAM(program, kVS, kFS); glUseProgram(program); GLint positionLocation = glGetAttribLocation(program, "position"); ASSERT_NE(-1, positionLocation); GLint redGreenLocation = glGetAttribLocation(program, "redGreen"); ASSERT_NE(-1, redGreenLocation); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffers[2]; glBindVertexArray(vertexArray); std::vector indices = {// 4 squares each made up of 6 vertices: // 1st square, in the upper-left part of window 0, 1, 2, 2, 3, 0, // 2nd square, in the upper-right part of window 4, 5, 6, 6, 7, 4, // 3rd square, in the lower-left part of window 8, 9, 10, 10, 11, 8, // 4th square, in the lower-right part of window 12, 13, 14, 14, 15, 12}; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indices.size(), &indices[0], GL_STATIC_DRAW); std::vector positionData = {// 4 squares each made up of quad vertices // 1st square, in the upper-left part of window -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, // 2nd square, in the upper-right part of window 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // 3rd square, in the lower-left part of window -1.0f, 0.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, // 4th square, in the lower-right part of window 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, -1.0f, 1.0f, 0.0f}; glBindBuffer(GL_ARRAY_BUFFER, vertexBuffers[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0], GL_STATIC_DRAW); glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr); glEnableVertexAttribArray(positionLocation); std::vector redGreenData = {// green(0,110), black(0,0), red(115,0), yellow(120,125) // 4 squares each made up of 4 pairs of half-color values: // 1st square, in the upper-left part of window 0.0f, 110.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 110.0f, // 2nd square, in the upper-right part of window 0.0f, 125.0f, 0.0f, 0.0f, 120.0f, 0.0f, 120.0f, 125.0f, // 3rd square, in the lower-left part of window 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, // 4th square, in the lower-right part of window 0.0f, 0.0f, 0.0f, 0.0f, 115.0f, 0.0f, 115.0f, 0.0f}; glBindBuffer(GL_ARRAY_BUFFER, vertexBuffers[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * redGreenData.size(), &redGreenData[0], GL_STATIC_DRAW); glVertexAttribPointer(redGreenLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr); glEnableVertexAttribArray(redGreenLocation); ASSERT_GL_NO_ERROR(); // Draw and check the 4 corner pixels, to ensure we're getting the expected "colors" glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, nullptr); GLColor expectedPixelLowerLeft(0, 0, 0, 255); GLColor expectedPixelLowerRight(229, 0, 0, 255); GLColor expectedPixelUpperLeft(0, 219, 0, 255); GLColor expectedPixelUpperRight(239, 249, 0, 255); EXPECT_PIXEL_COLOR_EQ(0, 0, expectedPixelLowerLeft); EXPECT_PIXEL_COLOR_EQ(mSize - 1, 0, expectedPixelLowerRight); EXPECT_PIXEL_COLOR_EQ(0, mSize - 1, expectedPixelUpperLeft); EXPECT_PIXEL_COLOR_EQ(mSize - 1, mSize - 1, expectedPixelUpperRight); ASSERT_GL_NO_ERROR(); // Make the image visible eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_EGL_SUCCESS(); // Draw again and check the 4 center pixels, to ensure we're getting the expected "colors" glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, nullptr); EXPECT_PIXEL_COLOR_EQ((mSize / 2) - 1, (mSize / 2) - 1, expectedPixelLowerLeft); EXPECT_PIXEL_COLOR_EQ((mSize / 2) - 1, (mSize / 2), expectedPixelUpperLeft); EXPECT_PIXEL_COLOR_EQ((mSize / 2), (mSize / 2) - 1, expectedPixelLowerRight); EXPECT_PIXEL_COLOR_EQ((mSize / 2), (mSize / 2), expectedPixelUpperRight); ASSERT_GL_NO_ERROR(); } // Android-specific test that changes a window's rotation, which requires ContextVk::syncState() to // handle the new rotation TEST_P(EGLPreRotationSurfaceTest, ChangeRotationWithDraw) { // This test uses functionality that is only available on Android ANGLE_SKIP_TEST_IF(isVulkanRenderer() && !IsAndroid()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); // Init program constexpr char kVS[] = "attribute vec2 position;\n" "attribute vec2 redGreen;\n" "varying vec2 v_data;\n" "void main() {\n" " gl_Position = vec4(position, 0, 1);\n" " v_data = redGreen;\n" "}"; constexpr char kFS[] = "varying highp vec2 v_data;\n" "void main() {\n" " gl_FragColor = vec4(v_data, 0, 1);\n" "}"; ANGLE_GL_PROGRAM(program, kVS, kFS); glUseProgram(program); GLint positionLocation = glGetAttribLocation(program, "position"); ASSERT_NE(-1, positionLocation); GLint redGreenLocation = glGetAttribLocation(program, "redGreen"); ASSERT_NE(-1, redGreenLocation); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffers[2]; glBindVertexArray(vertexArray); std::vector indices = {0, 1, 2, 2, 3, 0}; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indices.size(), &indices[0], GL_STATIC_DRAW); std::vector positionData = {// quad vertices -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f}; glBindBuffer(GL_ARRAY_BUFFER, vertexBuffers[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0], GL_STATIC_DRAW); glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr); glEnableVertexAttribArray(positionLocation); std::vector redGreenData = {// green(0,1), black(0,0), red(1,0), yellow(1,1) 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f}; glBindBuffer(GL_ARRAY_BUFFER, vertexBuffers[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * redGreenData.size(), &redGreenData[0], GL_STATIC_DRAW); glVertexAttribPointer(redGreenLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr); glEnableVertexAttribArray(redGreenLocation); ASSERT_GL_NO_ERROR(); // Change the rotation back and forth between landscape and portrait, and make sure that the // drawing and reading happen consistently with the desired rotation. // Last rotation needs to be portrait, since other tests expect it to be the default. for (int i = 0; i < 4; i++) { bool landscape; EGLint actualWidth = 0; EGLint actualHeight = 0; EGLint desiredWidth = 0; EGLint desiredHeight = 0; if ((i % 2) == 0) { landscape = true; desiredWidth = 300; desiredHeight = 200; } else { landscape = false; desiredWidth = 200; desiredHeight = 300; } mOSWindow->resize(desiredWidth, desiredHeight); // setOrientation() uses a reverse-JNI call, which sends data to other parts of Android. // Sometime later (i.e. asynchronously), the window is updated. Sleep a little here, and // then allow for multiple eglSwapBuffers calls to eventually see the new rotation. mOSWindow->setOrientation(desiredWidth, desiredHeight); angle::Sleep(1000); eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_EGL_SUCCESS(); while ((actualWidth != desiredWidth) && (actualHeight != desiredHeight)) { glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); if (landscape) { EXPECT_PIXEL_COLOR_EQ(mSize - 1, 0, GLColor::red); } else { EXPECT_PIXEL_COLOR_EQ(0, mSize - 1, GLColor::green); } ASSERT_GL_NO_ERROR(); eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_EGL_SUCCESS(); eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &actualHeight); eglQuerySurface(mDisplay, mWindowSurface, EGL_WIDTH, &actualWidth); } } } // A slight variation of EGLPreRotationSurfaceTest, where the initial window size is 400x300, yet // the drawing is still 256x256. In addition, gl_FragCoord is used in a "clever" way, as the color // of the 256x256 drawing area, which reproduces an interesting pre-rotation case from the // following dEQP tests: // // - dEQP.GLES31/functional_texture_multisample_samples_*_sample_position // // This will test the rotation of gl_FragCoord, as well as the viewport, scissor, and rendering // area calculations, especially when the Android device is rotated. class EGLPreRotationLargeSurfaceTest : public EGLPreRotationSurfaceTest { protected: EGLPreRotationLargeSurfaceTest() : mSize(256) {} void testSetUp() override { mOSWindow = OSWindow::New(); mOSWindow->initialize("EGLSurfaceTest", 400, 300); } int mSize; }; // Provide a predictable pattern for testing pre-rotation TEST_P(EGLPreRotationLargeSurfaceTest, OrientedWindowWithFragCoordDraw) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); // Init program constexpr char kVS[] = "attribute vec2 position;\n" "void main() {\n" " gl_Position = vec4(position, 0, 1);\n" "}"; constexpr char kFS[] = "void main() {\n" " gl_FragColor = vec4(gl_FragCoord.x / 256.0, gl_FragCoord.y / 256.0, 0.0, 1.0);\n" "}"; ANGLE_GL_PROGRAM(program, kVS, kFS); glUseProgram(program); GLint positionLocation = glGetAttribLocation(program, "position"); ASSERT_NE(-1, positionLocation); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffer; glBindVertexArray(vertexArray); std::vector indices = {0, 1, 2, 2, 3, 0}; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indices.size(), &indices[0], GL_STATIC_DRAW); std::vector positionData = {// quad vertices -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f}; glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0], GL_STATIC_DRAW); glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr); glEnableVertexAttribArray(positionLocation); ASSERT_GL_NO_ERROR(); glViewport(0, 0, mSize, mSize); testDrawingAndReadPixels(); } // Pre-rotation tests for glBlitFramebuffer. A slight variation of EGLPreRotationLargeSurfaceTest, // where the initial window size is still 400x300, and the drawing is still 256x256. In addition, // glBlitFramebuffer is tested in a variety of ways. Separate tests are used to make debugging // simpler, but they all share common setup. These tests reproduce interesting pre-rotation cases // from dEQP tests such as the following: // // - dEQP.GLES3/functional_fbo_blit_default_framebuffer_* // - dEQP.GLES3/functional_fbo_invalidate_* constexpr GLuint kCoordMidWayShort = 127; constexpr GLuint kCoordMidWayLong = 128; constexpr GLColor kColorMidWayShortShort = GLColor(127, 127, 0, 255); constexpr GLColor kColorMidWayShortLong = GLColor(127, 128, 0, 255); constexpr GLColor kColorMidWayLongShort = GLColor(128, 127, 0, 255); constexpr GLColor kColorMidWayLongLong = GLColor(128, 128, 0, 255); // When scaling horizontally, the "black" and "green" colors have a 1 in the red component constexpr GLColor kColorScaleHorizBlack = GLColor(1, 0, 0, 255); constexpr GLColor kColorScaleHorizGreen = GLColor(1, 255, 0, 255); // When scaling vertically, the "black" and "red" colors have a 1 in the green component constexpr GLColor kColorScaleVertBlack = GLColor(0, 1, 0, 255); constexpr GLColor kColorScaleVertRed = GLColor(255, 1, 0, 255); class EGLPreRotationBlitFramebufferTest : public EGLPreRotationLargeSurfaceTest { protected: EGLPreRotationBlitFramebufferTest() {} GLuint createProgram() { constexpr char kVS[] = "attribute vec2 position;\n" "attribute vec2 redGreen;\n" "varying vec2 v_data;\n" "void main() {\n" " gl_Position = vec4(position, 0, 1);\n" " v_data = redGreen;\n" "}"; constexpr char kFS[] = "varying highp vec2 v_data;\n" "void main() {\n" " gl_FragColor = vec4(v_data, 0, 1);\n" "}"; return CompileProgram(kVS, kFS); } void initializeGeometry(GLuint program, GLBuffer *indexBuffer, GLVertexArray *vertexArray, GLBuffer *vertexBuffers) { GLint positionLocation = glGetAttribLocation(program, "position"); ASSERT_NE(-1, positionLocation); GLint redGreenLocation = glGetAttribLocation(program, "redGreen"); ASSERT_NE(-1, redGreenLocation); glBindVertexArray(*vertexArray); std::vector indices = {0, 1, 2, 2, 3, 0}; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indices.size(), &indices[0], GL_STATIC_DRAW); std::vector positionData = {// quad vertices -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f}; glBindBuffer(GL_ARRAY_BUFFER, vertexBuffers[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0], GL_STATIC_DRAW); glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr); glEnableVertexAttribArray(positionLocation); std::vector redGreenData = {// green(0,1), black(0,0), red(1,0), yellow(1,1) 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f}; glBindBuffer(GL_ARRAY_BUFFER, vertexBuffers[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * redGreenData.size(), &redGreenData[0], GL_STATIC_DRAW); glVertexAttribPointer(redGreenLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr); glEnableVertexAttribArray(redGreenLocation); } void initializeFBO(GLFramebuffer *framebuffer, GLTexture *texture) { glBindTexture(GL_TEXTURE_2D, *texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mSize, mSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glBindFramebuffer(GL_FRAMEBUFFER, *framebuffer); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texture, 0); } // Ensures that the correct colors are where they should be when the entire 256x256 pattern has // been rendered or blitted to a location relative to an x and y offset. void test256x256PredictablePattern(GLint xOffset, GLint yOffset) { EXPECT_PIXEL_COLOR_EQ(xOffset + 0, yOffset + 0, GLColor::black); EXPECT_PIXEL_COLOR_EQ(xOffset + 0, yOffset + mSize - 1, GLColor::green); EXPECT_PIXEL_COLOR_EQ(xOffset + mSize - 1, yOffset + 0, GLColor::red); EXPECT_PIXEL_COLOR_EQ(xOffset + mSize - 1, yOffset + mSize - 1, GLColor::yellow); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayShort, yOffset + kCoordMidWayShort, kColorMidWayShortShort); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayShort, yOffset + kCoordMidWayLong, kColorMidWayShortLong); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayLong, yOffset + kCoordMidWayShort, kColorMidWayLongShort); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayLong, yOffset + kCoordMidWayLong, kColorMidWayLongLong); } }; // Draw a predictable pattern (for testing pre-rotation) into an FBO, and then use glBlitFramebuffer // to blit that pattern into various places within the 400x300 window TEST_P(EGLPreRotationBlitFramebufferTest, BasicBlitFramebuffer) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); // Init program GLuint program = createProgram(); ASSERT_NE(0u, program); glUseProgram(program); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffers[2]; initializeGeometry(program, &indexBuffer, &vertexArray, vertexBuffers); ASSERT_GL_NO_ERROR(); // Create a texture-backed FBO and render the predictable pattern to it GLFramebuffer fbo; GLTexture texture; initializeFBO(&fbo, &texture); ASSERT_GL_NO_ERROR(); glViewport(0, 0, mSize, mSize); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); ASSERT_GL_NO_ERROR(); // Ensure the predictable pattern seems correct in the FBO test256x256PredictablePattern(0, 0); ASSERT_GL_NO_ERROR(); // // Test blitting the entire FBO image to a 256x256 part of the default framebuffer (no scaling) // // Blit from the FBO to the default framebuffer (i.e. the swapchain) glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize, 0, 0, mSize, mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); ASSERT_GL_NO_ERROR(); // Swap buffers to put the image in the window (so the test can be visually checked) eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); // Blit again to check the colors in the back buffer glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize, 0, 0, mSize, mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); test256x256PredictablePattern(0, 0); ASSERT_GL_NO_ERROR(); // Clear to black and blit to a different part of the window glClear(GL_COLOR_BUFFER_BIT); GLint xOffset = 40; GLint yOffset = 30; glViewport(xOffset, yOffset, mSize, mSize); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Swap buffers to put the image in the window (so the test can be visually checked) eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); // Blit again to check the colors in the back buffer glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); test256x256PredictablePattern(xOffset, yOffset); ASSERT_GL_NO_ERROR(); ASSERT_EGL_SUCCESS(); } // Blit the ms0 stencil buffer to the default framebuffer with rotation on android. TEST_P(EGLPreRotationBlitFramebufferTest, BlitStencilWithRotation) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888d24s8Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); mOSWindow->setOrientation(300, 400); angle::Sleep(1000); eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_EGL_SUCCESS(); GLRenderbuffer colorbuf; glBindRenderbuffer(GL_RENDERBUFFER, colorbuf.get()); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_RGBA8, 64, 128); GLRenderbuffer depthstencilbuf; glBindRenderbuffer(GL_RENDERBUFFER, depthstencilbuf.get()); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_DEPTH24_STENCIL8, 64, 128); GLFramebuffer framebuffer; glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthstencilbuf); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencilbuf); glCheckFramebufferStatus(GL_FRAMEBUFFER); glClearColor(1.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Replace stencil to 1. ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); glEnable(GL_STENCIL_TEST); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilFunc(GL_ALWAYS, 1, 255); drawQuad(drawRed.get(), essl3_shaders::PositionAttrib(), 0.8f); // Blit stencil buffer to default frambuffer. GLenum attachments1[] = {GL_COLOR_ATTACHMENT0}; glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments1); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBlitFramebuffer(0, 0, 64, 128, 0, 0, 64, 128, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); ANGLE_GL_PROGRAM(drawGreen, essl3_shaders::vs::Simple(), essl3_shaders::fs::Green()); glDisable(GL_STENCIL_TEST); drawQuad(drawGreen.get(), essl3_shaders::PositionAttrib(), 0.5f); // Draw blue color if the stencil is equal to 1. // If the blit finished successfully, the stencil test should all pass. ANGLE_GL_PROGRAM(drawBlue, essl3_shaders::vs::Simple(), essl3_shaders::fs::Blue()); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_EQUAL, 1, 255); drawQuad(drawBlue.get(), essl3_shaders::PositionAttrib(), 0.3f); // Check the result, especially the boundaries. EXPECT_PIXEL_COLOR_EQ(0, 127, GLColor::blue); EXPECT_PIXEL_COLOR_EQ(32, 127, GLColor::blue); EXPECT_PIXEL_COLOR_EQ(32, 0, GLColor::blue); EXPECT_PIXEL_COLOR_EQ(63, 0, GLColor::blue); EXPECT_PIXEL_COLOR_EQ(63, 64, GLColor::blue); EXPECT_PIXEL_COLOR_EQ(32, 64, GLColor::blue); // Some pixels around x=0/63 (related to the pre-rotation degree) still fail on android. // From the image in the window, the failures near one of the image's edge look like "aliasing". // We need to fix blit with pre-rotation. http://anglebug.com/5044 // EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); // EXPECT_PIXEL_COLOR_EQ(0, 64, GLColor::blue); // EXPECT_PIXEL_COLOR_EQ(63, 1, GLColor::blue); // EXPECT_PIXEL_COLOR_EQ(63, 127, GLColor::blue); eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); } // Blit the multisample stencil buffer to the default framebuffer with rotation on android. TEST_P(EGLPreRotationBlitFramebufferTest, BlitMultisampleStencilWithRotation) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888d24s8Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); mOSWindow->setOrientation(300, 400); angle::Sleep(1000); eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_EGL_SUCCESS(); GLRenderbuffer colorbuf; glBindRenderbuffer(GL_RENDERBUFFER, colorbuf.get()); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, 128, 64); GLRenderbuffer depthstencilbuf; glBindRenderbuffer(GL_RENDERBUFFER, depthstencilbuf.get()); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, 128, 64); GLFramebuffer framebuffer; glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthstencilbuf); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencilbuf); glCheckFramebufferStatus(GL_FRAMEBUFFER); glClearColor(1.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Replace stencil to 1. ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); glEnable(GL_STENCIL_TEST); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilFunc(GL_ALWAYS, 1, 255); drawQuad(drawRed.get(), essl3_shaders::PositionAttrib(), 0.8f); // Blit multisample stencil buffer to default frambuffer. GLenum attachments1[] = {GL_COLOR_ATTACHMENT0}; glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments1); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBlitFramebuffer(0, 0, 128, 64, 0, 0, 128, 64, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); ANGLE_GL_PROGRAM(drawGreen, essl3_shaders::vs::Simple(), essl3_shaders::fs::Green()); glDisable(GL_STENCIL_TEST); drawQuad(drawGreen.get(), essl3_shaders::PositionAttrib(), 0.5f); // Draw blue color if the stencil is equal to 1. // If the blit finished successfully, the stencil test should all pass. ANGLE_GL_PROGRAM(drawBlue, essl3_shaders::vs::Simple(), essl3_shaders::fs::Blue()); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_EQUAL, 1, 255); drawQuad(drawBlue.get(), essl3_shaders::PositionAttrib(), 0.3f); // Check the result, especially the boundaries. EXPECT_PIXEL_COLOR_EQ(127, 32, GLColor::blue); EXPECT_PIXEL_COLOR_EQ(64, 32, GLColor::blue); EXPECT_PIXEL_COLOR_EQ(0, 63, GLColor::blue); EXPECT_PIXEL_COLOR_EQ(64, 63, GLColor::blue); // Some pixels around x=0/127 or y=0 (related to the pre-rotation degree)still fail on android. // We need to fix blit with pre-rotation. http://anglebug.com/5044 // Failures of Rotated90Degrees. // EXPECT_PIXEL_COLOR_EQ(127, 1, GLColor::blue); // EXPECT_PIXEL_COLOR_EQ(127, 63, GLColor::blue); // Failures of Rotated180Degrees. // EXPECT_PIXEL_COLOR_EQ(64, 0, GLColor::blue); // EXPECT_PIXEL_COLOR_EQ(127, 0, GLColor::blue); // Failures of Rotated270Degrees. // EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); // EXPECT_PIXEL_COLOR_EQ(0, 32, GLColor::blue); eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); } // Blit stencil to default framebuffer with flip and prerotation. TEST_P(EGLPreRotationBlitFramebufferTest, BlitStencilWithFlip) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // We need to fix blit with pre-rotation. http://anglebug.com/5044 ANGLE_SKIP_TEST_IF(IsAndroid() || IsWindows()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888d24s8Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); mOSWindow->setOrientation(300, 400); angle::Sleep(1000); eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_EGL_SUCCESS(); constexpr int kSize = 128; glViewport(0, 0, kSize, kSize); GLRenderbuffer colorbuf; glBindRenderbuffer(GL_RENDERBUFFER, colorbuf.get()); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_RGBA8, kSize, kSize); GLRenderbuffer depthstencilbuf; glBindRenderbuffer(GL_RENDERBUFFER, depthstencilbuf.get()); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_DEPTH24_STENCIL8, kSize, kSize); GLFramebuffer framebuffer; glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthstencilbuf); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencilbuf); glCheckFramebufferStatus(GL_FRAMEBUFFER); glClearColor(1.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Replace stencil to 1. ANGLE_GL_PROGRAM(drawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); glEnable(GL_STENCIL_TEST); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilFunc(GL_ALWAYS, 1, 255); drawQuad(drawRed.get(), essl3_shaders::PositionAttrib(), 0.8f); // Blit stencil buffer to default frambuffer with X-flip. GLenum attachments1[] = {GL_COLOR_ATTACHMENT0}; glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments1); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBlitFramebuffer(0, 0, kSize, kSize, kSize, 0, 0, kSize, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); ANGLE_GL_PROGRAM(drawGreen, essl3_shaders::vs::Simple(), essl3_shaders::fs::Green()); glDisable(GL_STENCIL_TEST); drawQuad(drawGreen.get(), essl3_shaders::PositionAttrib(), 0.5f); // Draw blue color if the stencil is equal to 1. // If the blit finished successfully, the stencil test should all pass. glEnable(GL_STENCIL_TEST); glStencilFunc(GL_EQUAL, 1, 255); ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(), essl31_shaders::fs::RedGreenGradient()); drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); // Check the result, especially the boundaries. EXPECT_PIXEL_NEAR(0, 0, 0, 0, 0, 255, 1.0); // Black EXPECT_PIXEL_NEAR(kSize - 1, 0, 253, 0, 0, 255, 1.0); // Red EXPECT_PIXEL_NEAR(0, kSize - 1, 0, 253, 0, 255, 1.0); // Green EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 253, 253, 0, 255, 1.0); // Yellow eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); } // Blit color buffer to default framebuffer with Y-flip/X-flip. TEST_P(EGLPreRotationBlitFramebufferTest, BlitColorToDefault) { // This test uses functionality that is only available on Android ANGLE_SKIP_TEST_IF(isVulkanRenderer() && !IsAndroid()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); constexpr int kSize = 128; glViewport(0, 0, kSize, kSize); GLRenderbuffer colorbuf; glBindRenderbuffer(GL_RENDERBUFFER, colorbuf.get()); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_RGBA8, kSize, kSize); GLFramebuffer framebuffer; glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf); glCheckFramebufferStatus(GL_FRAMEBUFFER); glClearColor(1.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(), essl31_shaders::fs::RedGreenGradient()); EGLint desiredWidth = 300; EGLint desiredHeight = 400; mOSWindow->resize(desiredWidth, desiredHeight); mOSWindow->setOrientation(desiredWidth, desiredHeight); angle::Sleep(1000); eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_EGL_SUCCESS(); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.get()); drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); // Blit color buffer to default frambuffer without flip. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); // Check the result, especially the boundaries. EXPECT_PIXEL_NEAR(0, 0, 0, 0, 0, 255, 1.0); // Balck EXPECT_PIXEL_NEAR(kSize - 1, 0, 253, 0, 0, 255, 1.0); // Red EXPECT_PIXEL_NEAR(0, kSize - 1, 0, 253, 0, 255, 1.0); // Green EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 253, 253, 0, 255, 1.0); // Yellow // Blit color buffer to default frambuffer with Y-flip. glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer.get()); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBlitFramebuffer(0, 0, kSize, kSize, 0, kSize, kSize, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); EXPECT_PIXEL_NEAR(0, 0, 0, 253, 0, 255, 1.0); // Green EXPECT_PIXEL_NEAR(kSize - 1, 0, 253, 253, 0, 255, 1.0); // Yellow EXPECT_PIXEL_NEAR(0, kSize - 1, 0, 0, 0, 255, 1.0); // Balck EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 253, 0, 0, 255, 1.0); // Red // Blit color buffer to default frambuffer with X-flip. glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer.get()); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBlitFramebuffer(0, 0, kSize, kSize, kSize, 0, 0, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); EXPECT_PIXEL_NEAR(0, 0, 253, 0, 0, 255, 1.0); // Red EXPECT_PIXEL_NEAR(kSize - 1, 0, 0, 0, 0, 255, 1.0); // Balck EXPECT_PIXEL_NEAR(0, kSize - 1, 253, 253, 0, 255, 1.0); // Yellow EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 0, 253, 0, 255, 1.0); // Green ASSERT_GL_NO_ERROR(); } // Blit color buffer from default framebuffer with Y-flip/X-flip. TEST_P(EGLPreRotationBlitFramebufferTest, BlitColorFromDefault) { // This test uses functionality that is only available on Android ANGLE_SKIP_TEST_IF(isVulkanRenderer() && !IsAndroid()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); constexpr int kSize = 128; glViewport(0, 0, kSize, kSize); GLRenderbuffer colorbuf; glBindRenderbuffer(GL_RENDERBUFFER, colorbuf.get()); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_RGBA8, kSize, kSize); GLFramebuffer framebuffer; glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf); glCheckFramebufferStatus(GL_FRAMEBUFFER); glClearColor(1.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(), essl31_shaders::fs::RedGreenGradient()); EGLint desiredWidth = 300; EGLint desiredHeight = 400; mOSWindow->resize(desiredWidth, desiredHeight); mOSWindow->setOrientation(desiredWidth, desiredHeight); angle::Sleep(1000); eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_EGL_SUCCESS(); glBindFramebuffer(GL_FRAMEBUFFER, 0); drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); // Blit color buffer from default frambuffer without flip. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.get()); glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer.get()); // Check the result, especially the boundaries. EXPECT_PIXEL_NEAR(0, 0, 0, 0, 0, 255, 1.0); // Balck EXPECT_PIXEL_NEAR(kSize - 1, 0, 253, 0, 0, 255, 1.0); // Red EXPECT_PIXEL_NEAR(0, kSize - 1, 0, 253, 0, 255, 1.0); // Green EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 253, 253, 0, 255, 1.0); // Yellow // Blit color buffer from default frambuffer with Y-flip. glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.get()); glBlitFramebuffer(0, 0, kSize, kSize, 0, kSize, kSize, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer.get()); EXPECT_PIXEL_NEAR(0, 0, 0, 253, 0, 255, 1.0); // Green EXPECT_PIXEL_NEAR(kSize - 1, 0, 253, 253, 0, 255, 1.0); // Yellow EXPECT_PIXEL_NEAR(0, kSize - 1, 0, 0, 0, 255, 1.0); // Balck EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 253, 0, 0, 255, 1.0); // Red // Blit color buffer from default frambuffer with X-flip. glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.get()); glBlitFramebuffer(0, 0, kSize, kSize, kSize, 0, 0, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer.get()); EXPECT_PIXEL_NEAR(0, 0, 253, 0, 0, 255, 1.0); // Red EXPECT_PIXEL_NEAR(kSize - 1, 0, 0, 0, 0, 255, 1.0); // Balck EXPECT_PIXEL_NEAR(0, kSize - 1, 253, 253, 0, 255, 1.0); // Yellow EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 0, 253, 0, 255, 1.0); // Green ASSERT_GL_NO_ERROR(); } // Blit multisample color buffer to resolved framebuffer. TEST_P(EGLPreRotationBlitFramebufferTest, BlitMultisampleColorToResolved) { // This test uses functionality that is only available on Android ANGLE_SKIP_TEST_IF(isVulkanRenderer() && !IsAndroid()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); constexpr int kSize = 128; glViewport(0, 0, kSize, kSize); GLRenderbuffer colorMS; glBindRenderbuffer(GL_RENDERBUFFER, colorMS.get()); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, kSize, kSize); GLRenderbuffer colorResolved; glBindRenderbuffer(GL_RENDERBUFFER, colorResolved.get()); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kSize, kSize); GLFramebuffer framebufferMS; glBindFramebuffer(GL_FRAMEBUFFER, framebufferMS.get()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorMS); glCheckFramebufferStatus(GL_FRAMEBUFFER); glClearColor(1.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(), essl31_shaders::fs::RedGreenGradient()); drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); GLFramebuffer framebufferResolved; glBindFramebuffer(GL_FRAMEBUFFER, framebufferResolved.get()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorResolved.get()); EGLint desiredWidth = 300; EGLint desiredHeight = 400; mOSWindow->resize(desiredWidth, desiredHeight); mOSWindow->setOrientation(desiredWidth, desiredHeight); angle::Sleep(1000); eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_EGL_SUCCESS(); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebufferMS.get()); drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferMS.get()); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebufferResolved.get()); glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferResolved.get()); // Check the result, especially the boundaries. EXPECT_PIXEL_NEAR(0, 0, 0, 0, 0, 255, 1.0); // Balck EXPECT_PIXEL_NEAR(kSize - 1, 0, 253, 0, 0, 255, 1.0); // Red EXPECT_PIXEL_NEAR(0, kSize - 1, 0, 253, 0, 255, 1.0); // Green EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 253, 253, 0, 255, 1.0); // Yellow ASSERT_GL_NO_ERROR(); } // Blit color buffer to default framebuffer with linear filter. TEST_P(EGLPreRotationBlitFramebufferTest, BlitColorWithLinearFilter) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); mOSWindow->setOrientation(300, 400); angle::Sleep(1000); eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_EGL_SUCCESS(); constexpr int kSize = 128; glViewport(0, 0, kSize, kSize); GLRenderbuffer colorbuf; glBindRenderbuffer(GL_RENDERBUFFER, colorbuf.get()); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_RGBA8, kSize, kSize); GLFramebuffer framebuffer; glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf); glCheckFramebufferStatus(GL_FRAMEBUFFER); glClearColor(1.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); ANGLE_GL_PROGRAM(gradientProgram, essl31_shaders::vs::Passthrough(), essl31_shaders::fs::RedGreenGradient()); drawQuad(gradientProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_LINEAR); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); // Check the result, especially the boundaries. EXPECT_PIXEL_NEAR(0, 0, 0, 0, 0, 255, 1.0); // Black EXPECT_PIXEL_NEAR(kSize - 1, 0, 253, 0, 0, 255, 1.0); // Red EXPECT_PIXEL_NEAR(0, kSize - 1, 0, 253, 0, 255, 1.0); // Green EXPECT_PIXEL_NEAR(kSize - 1, kSize - 1, 253, 253, 0, 255, 1.0); // Yellow eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); } // Draw a predictable pattern (for testing pre-rotation) into an FBO, and then use glBlitFramebuffer // to blit the left and right halves of that pattern into various places within the 400x300 window TEST_P(EGLPreRotationBlitFramebufferTest, LeftAndRightBlitFramebuffer) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); // Init program GLuint program = createProgram(); ASSERT_NE(0u, program); glUseProgram(program); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffers[2]; initializeGeometry(program, &indexBuffer, &vertexArray, vertexBuffers); ASSERT_GL_NO_ERROR(); // Create a texture-backed FBO and render the predictable pattern to it GLFramebuffer fbo; GLTexture texture; initializeFBO(&fbo, &texture); ASSERT_GL_NO_ERROR(); glViewport(0, 0, mSize, mSize); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); ASSERT_GL_NO_ERROR(); // Ensure the predictable pattern seems correct in the FBO test256x256PredictablePattern(0, 0); ASSERT_GL_NO_ERROR(); // Prepare to blit to the default framebuffer and read from the FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Blit to an offset part of the 400x300 window GLint xOffset = 40; GLint yOffset = 30; // // Test blitting half of the FBO image to a 128x256 or 256x128 part of the default framebuffer // (no scaling) // // 1st) Clear to black and blit the left and right halves of the texture to the left and right // halves of that different part of the window glClear(GL_COLOR_BUFFER_BIT); glViewport(xOffset, yOffset, mSize, mSize); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBlitFramebuffer(0, 0, mSize / 2, mSize, xOffset, yOffset, xOffset + (mSize / 2), yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(mSize / 2, 0, mSize, mSize, xOffset + (mSize / 2), yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Swap buffers to put the image in the window (so the test can be visually checked) eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); // Blit again to check the colors in the back buffer glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize / 2, mSize, xOffset, yOffset, xOffset + (mSize / 2), yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(mSize / 2, 0, mSize, mSize, xOffset + (mSize / 2), yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); test256x256PredictablePattern(xOffset, yOffset); ASSERT_GL_NO_ERROR(); // 2nd) Clear to black and this time blit the left half of the source texture to the right half // of the destination window, and then blit the right half of the source texture to the left // half of the destination window glClear(GL_COLOR_BUFFER_BIT); glViewport(xOffset, yOffset, mSize, mSize); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBlitFramebuffer(mSize / 2, 0, mSize, mSize, xOffset, yOffset, xOffset + (mSize / 2), yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(0, 0, mSize / 2, mSize, xOffset + (mSize / 2), yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Swap buffers to put the image in the window (so the test can be visually checked) eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); // Blit again to check the colors in the back buffer glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(mSize / 2, 0, mSize, mSize, xOffset, yOffset, xOffset + (mSize / 2), yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(0, 0, mSize / 2, mSize, xOffset + (mSize / 2), yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayShort + 1, yOffset + 0, GLColor::black); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayShort + 1, yOffset + mSize - 1, GLColor::green); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayShort, yOffset + 0, GLColor::red); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayShort, yOffset + mSize - 1, GLColor::yellow); EXPECT_PIXEL_COLOR_EQ(xOffset + mSize - 1, yOffset + kCoordMidWayShort, kColorMidWayShortShort); EXPECT_PIXEL_COLOR_EQ(xOffset + mSize - 1, yOffset + kCoordMidWayLong, kColorMidWayShortLong); EXPECT_PIXEL_COLOR_EQ(xOffset + 0, yOffset + kCoordMidWayShort, kColorMidWayLongShort); EXPECT_PIXEL_COLOR_EQ(xOffset + 0, yOffset + kCoordMidWayLong, kColorMidWayLongLong); ASSERT_GL_NO_ERROR(); ASSERT_EGL_SUCCESS(); } // Draw a predictable pattern (for testing pre-rotation) into an FBO, and then use glBlitFramebuffer // to blit the top and bottom halves of that pattern into various places within the 400x300 window TEST_P(EGLPreRotationBlitFramebufferTest, TopAndBottomBlitFramebuffer) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); // Init program GLuint program = createProgram(); ASSERT_NE(0u, program); glUseProgram(program); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffers[2]; initializeGeometry(program, &indexBuffer, &vertexArray, vertexBuffers); ASSERT_GL_NO_ERROR(); // Create a texture-backed FBO and render the predictable pattern to it GLFramebuffer fbo; GLTexture texture; initializeFBO(&fbo, &texture); ASSERT_GL_NO_ERROR(); glViewport(0, 0, mSize, mSize); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); ASSERT_GL_NO_ERROR(); // Ensure the predictable pattern seems correct in the FBO test256x256PredictablePattern(0, 0); ASSERT_GL_NO_ERROR(); // Prepare to blit to the default framebuffer and read from the FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Blit to an offset part of the 400x300 window GLint xOffset = 40; GLint yOffset = 30; // // Test blitting half of the FBO image to a 128x256 or 256x128 part of the default framebuffer // (no scaling) // // 1st) Clear to black and blit the top and bottom halves of the texture to the top and bottom // halves of that different part of the window glClear(GL_COLOR_BUFFER_BIT); glViewport(xOffset, yOffset, mSize, mSize); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBlitFramebuffer(0, 0, mSize, mSize / 2, xOffset, yOffset, xOffset + mSize, yOffset + (mSize / 2), GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(0, mSize / 2, mSize, mSize, xOffset, yOffset + (mSize / 2), xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Swap buffers to put the image in the window (so the test can be visually checked) eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); // Blit again to check the colors in the back buffer glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize / 2, xOffset, yOffset, xOffset + mSize, yOffset + (mSize / 2), GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(0, mSize / 2, mSize, mSize, xOffset, yOffset + (mSize / 2), xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); test256x256PredictablePattern(xOffset, yOffset); ASSERT_GL_NO_ERROR(); // 2nd) Clear to black and this time blit the top half of the source texture to the bottom half // of the destination window, and then blit the bottom half of the source texture to the top // half of the destination window glClear(GL_COLOR_BUFFER_BIT); glViewport(xOffset, yOffset, mSize, mSize); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBlitFramebuffer(0, 0, mSize, mSize / 2, xOffset, yOffset + (mSize / 2), xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(0, mSize / 2, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + (mSize / 2), GL_COLOR_BUFFER_BIT, GL_NEAREST); // Swap buffers to put the image in the window (so the test can be visually checked) eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); // Blit again to check the colors in the back buffer glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize / 2, xOffset, yOffset + (mSize / 2), xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(0, mSize / 2, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + (mSize / 2), GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); EXPECT_PIXEL_COLOR_EQ(xOffset + 0, yOffset + kCoordMidWayShort + 1, GLColor::black); EXPECT_PIXEL_COLOR_EQ(xOffset + 0, yOffset + kCoordMidWayShort, GLColor::green); EXPECT_PIXEL_COLOR_EQ(xOffset + mSize - 1, yOffset + kCoordMidWayShort + 1, GLColor::red); EXPECT_PIXEL_COLOR_EQ(xOffset + mSize - 1, yOffset + kCoordMidWayShort, GLColor::yellow); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayShort, yOffset + mSize - 1, kColorMidWayShortShort); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayShort, yOffset + 0, kColorMidWayShortLong); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayLong, yOffset + mSize - 1, kColorMidWayLongShort); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayLong, yOffset + 0, kColorMidWayLongLong); ASSERT_GL_NO_ERROR(); ASSERT_EGL_SUCCESS(); } // Draw a predictable pattern (for testing pre-rotation) into an FBO, and then use glBlitFramebuffer // to blit that pattern into various places within the 400x300 window, but being scaled to one-half // size TEST_P(EGLPreRotationBlitFramebufferTest, ScaledBlitFramebuffer) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); // Init program GLuint program = createProgram(); ASSERT_NE(0u, program); glUseProgram(program); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffers[2]; initializeGeometry(program, &indexBuffer, &vertexArray, vertexBuffers); ASSERT_GL_NO_ERROR(); // Create a texture-backed FBO and render the predictable pattern to it GLFramebuffer fbo; GLTexture texture; initializeFBO(&fbo, &texture); ASSERT_GL_NO_ERROR(); glViewport(0, 0, mSize, mSize); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); ASSERT_GL_NO_ERROR(); // Ensure the predictable pattern seems correct in the FBO test256x256PredictablePattern(0, 0); ASSERT_GL_NO_ERROR(); // Prepare to blit to the default framebuffer and read from the FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Blit to an offset part of the 400x300 window GLint xOffset = 40; GLint yOffset = 30; // // Test blitting the entire FBO image to a 128x256 or 256x128 part of the default framebuffer // (requires scaling) // // 1st) Clear to black and blit the FBO to the left and right halves of that different part of // the window glClear(GL_COLOR_BUFFER_BIT); glViewport(xOffset, yOffset, mSize, mSize); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + (mSize / 2), yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(0, 0, mSize, mSize, xOffset + (mSize / 2), yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Swap buffers to put the image in the window (so the test can be visually checked) eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); // Blit again to check the colors in the back buffer glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + (mSize / 2), yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(0, 0, mSize, mSize, xOffset + (mSize / 2), yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); EXPECT_PIXEL_COLOR_EQ(xOffset + 0, yOffset + 0, kColorScaleHorizBlack); EXPECT_PIXEL_COLOR_EQ(xOffset + 0, yOffset + mSize - 1, kColorScaleHorizGreen); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayShort, yOffset + 0, GLColor::red); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayShort, yOffset + mSize - 1, GLColor::yellow); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayLong, yOffset + 0, kColorScaleHorizBlack); EXPECT_PIXEL_COLOR_EQ(xOffset + kCoordMidWayLong, yOffset + mSize - 1, kColorScaleHorizGreen); EXPECT_PIXEL_COLOR_EQ(xOffset + mSize - 1, yOffset + 0, GLColor::red); EXPECT_PIXEL_COLOR_EQ(xOffset + mSize - 1, yOffset + mSize - 1, GLColor::yellow); // 2nd) Clear to black and blit the FBO to the top and bottom halves of that different part of // the window glClear(GL_COLOR_BUFFER_BIT); glViewport(xOffset, yOffset, mSize, mSize); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + (mSize / 2), GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset + (mSize / 2), xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Swap buffers to put the image in the window (so the test can be visually checked) eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); // Blit again to check the colors in the back buffer glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + (mSize / 2), GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset + (mSize / 2), xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); EXPECT_PIXEL_COLOR_EQ(xOffset + 0, yOffset + 0, kColorScaleVertBlack); EXPECT_PIXEL_COLOR_EQ(xOffset + mSize - 1, yOffset + 0, kColorScaleVertRed); EXPECT_PIXEL_COLOR_EQ(xOffset + 0, yOffset + kCoordMidWayShort, GLColor::green); EXPECT_PIXEL_COLOR_EQ(xOffset + mSize - 1, yOffset + kCoordMidWayShort, GLColor::yellow); EXPECT_PIXEL_COLOR_EQ(xOffset + 0, yOffset + kCoordMidWayLong, kColorScaleVertBlack); EXPECT_PIXEL_COLOR_EQ(xOffset + mSize - 1, yOffset + kCoordMidWayLong, kColorScaleVertRed); EXPECT_PIXEL_COLOR_EQ(xOffset + 0, yOffset + mSize - 1, GLColor::green); EXPECT_PIXEL_COLOR_EQ(xOffset + mSize - 1, yOffset + mSize - 1, GLColor::yellow); ASSERT_GL_NO_ERROR(); ASSERT_EGL_SUCCESS(); } // Draw a predictable pattern (for testing pre-rotation) into a 256x256 portion of the 400x300 // window, and then use glBlitFramebuffer to blit that pattern into an FBO TEST_P(EGLPreRotationBlitFramebufferTest, FboDestBlitFramebuffer) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); // Init program GLuint program = createProgram(); ASSERT_NE(0u, program); glUseProgram(program); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffers[2]; initializeGeometry(program, &indexBuffer, &vertexArray, vertexBuffers); ASSERT_GL_NO_ERROR(); // Create a texture-backed FBO and render the predictable pattern to it GLFramebuffer fbo; GLTexture texture; initializeFBO(&fbo, &texture); ASSERT_GL_NO_ERROR(); glViewport(0, 0, mSize, mSize); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); ASSERT_GL_NO_ERROR(); // Ensure the predictable pattern seems correct in the FBO test256x256PredictablePattern(0, 0); ASSERT_GL_NO_ERROR(); // Prepare to blit to the default framebuffer and read from the FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Blit to an offset part of the 400x300 window GLint xOffset = 40; GLint yOffset = 30; // // Test blitting a 256x256 part of the default framebuffer to the entire FBO (no scaling) // // To get the entire predictable pattern into the default framebuffer at the desired offset, // blit it from the FBO glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glViewport(xOffset, yOffset, mSize, mSize); glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Swap buffers to put the image in the window (so the test can be visually checked) eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); // Blit again to check the colors in the back buffer glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Clear the FBO to black and blit from the window to the FBO glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); glViewport(0, 0, mSize, mSize); glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(xOffset, yOffset, xOffset + mSize, yOffset + mSize, 0, 0, mSize, mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Ensure the predictable pattern seems correct in the FBO glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); test256x256PredictablePattern(0, 0); ASSERT_GL_NO_ERROR(); ASSERT_EGL_SUCCESS(); } // Draw a predictable pattern (for testing pre-rotation) into a 256x256 portion of the 400x300 // window, and then use glBlitFramebuffer to blit that pattern into an FBO, but with coordinates // that are partially out-of-bounds of the source TEST_P(EGLPreRotationBlitFramebufferTest, FboDestOutOfBoundsSourceBlitFramebuffer) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); // Init program GLuint program = createProgram(); ASSERT_NE(0u, program); glUseProgram(program); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffers[2]; initializeGeometry(program, &indexBuffer, &vertexArray, vertexBuffers); ASSERT_GL_NO_ERROR(); // Create a texture-backed FBO and render the predictable pattern to it GLFramebuffer fbo; GLTexture texture; initializeFBO(&fbo, &texture); ASSERT_GL_NO_ERROR(); glViewport(0, 0, mSize, mSize); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); ASSERT_GL_NO_ERROR(); // Ensure the predictable pattern seems correct in the FBO test256x256PredictablePattern(0, 0); ASSERT_GL_NO_ERROR(); // Prepare to blit to the default framebuffer and read from the FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Blit to the origin of the 400x300 window GLint xOffset = 0; GLint yOffset = 0; // // Test blitting a 256x256 part of the default framebuffer to the entire FBO (no scaling) // // To get the entire predictable pattern into the default framebuffer at the desired offset, // blit it from the FBO glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glViewport(xOffset, yOffset, mSize, mSize); glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Swap buffers to put the image in the window (so the test can be visually checked) eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); // Blit again to check the colors in the back buffer glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Clear the FBO to black and blit from the window to the FBO, but give source coordinates that // are partially outside of the window xOffset = -10; yOffset = -15; glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); glViewport(0, 0, mSize, mSize); glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(xOffset, yOffset, xOffset + mSize, yOffset + mSize, 0, 0, mSize, mSize, GL_COLOR_BUFFER_BIT, GL_LINEAR); // Ensure the predictable pattern seems correct in the FBO glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); // NOTE: There is a strip of black on the left and bottom edges of the PBO, corresponding to // the source coordinates that were outside of the source. The strip of black is xOffset // pixels wide on the left side, and yOffset pixels tall on the bottom side. EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); EXPECT_PIXEL_COLOR_EQ(0, 255, GLColor::black); EXPECT_PIXEL_COLOR_EQ(-xOffset - 1, 0, GLColor::black); EXPECT_PIXEL_COLOR_EQ(-xOffset - 1, 255, GLColor::black); EXPECT_PIXEL_COLOR_EQ(0, -yOffset - 1, GLColor::black); EXPECT_PIXEL_COLOR_EQ(255, -yOffset - 1, GLColor::black); EXPECT_PIXEL_COLOR_EQ(255 + xOffset, 0, GLColor::black); EXPECT_PIXEL_COLOR_EQ(255 + xOffset, -yOffset - 1, GLColor::black); EXPECT_PIXEL_COLOR_EQ(0, 255 + yOffset, GLColor::black); EXPECT_PIXEL_COLOR_EQ(-xOffset - 1, 255 + yOffset, GLColor::black); // FBO coordinate (-xOffset, -yOffset) (or (10, 15)) has the values from the bottom-left corner // of the source (which happens to be black). Thus, the following two tests are equivalent: EXPECT_PIXEL_COLOR_EQ(-xOffset, -yOffset, GLColor::black); EXPECT_PIXEL_COLOR_EQ(10, 15, GLColor::black); // Note: the following is equivalent to (0, 0): EXPECT_PIXEL_COLOR_EQ(10 + xOffset, 15 + yOffset, GLColor::black); EXPECT_PIXEL_COLOR_EQ(-xOffset + 1, -yOffset + 1, GLColor(1, 1, 0, 255)); EXPECT_PIXEL_COLOR_EQ(-xOffset + 10, -yOffset + 10, GLColor(10, 10, 0, 255)); EXPECT_PIXEL_COLOR_EQ(-xOffset + 20, -yOffset + 20, GLColor(20, 20, 0, 255)); EXPECT_PIXEL_COLOR_EQ(-xOffset + 100, -yOffset + 100, GLColor(100, 100, 0, 255)); EXPECT_PIXEL_COLOR_EQ(-xOffset + 200, -yOffset + 200, GLColor(200, 200, 0, 255)); EXPECT_PIXEL_COLOR_EQ(-xOffset + 230, -yOffset + 230, GLColor(230, 230, 0, 255)); // Note how the offset works differently when added to the same coordinate value as above. The // black strip causes the value to be 2X less the offset in each direction. Thus, coordinate // (230+xOffset, 230+yOffset) yields actual coordinate (220, 215) and red-green values // (230+(2*xOffset), 230+(2*yOffset)) or (210, 200). The following two tests are equivalent: EXPECT_PIXEL_COLOR_EQ(230 + xOffset, 230 + yOffset, GLColor(230 + (2 * xOffset), 230 + (2 * yOffset), 0, 255)); EXPECT_PIXEL_COLOR_EQ(220, 215, GLColor(210, 200, 0, 255)); // FBO coordinate (245, 240) has the highest pixel values from the source. The value of the // FBO pixel at (245, 240) is smaller than the same coordinate in the source because of the // blit's offsets. That is, the value is (245-xOffset, 240-yOffset) or (235, 225). Thus, the // following two tests are the same: EXPECT_PIXEL_COLOR_EQ(255 + xOffset, 255 + yOffset, GLColor(255 + (2 * xOffset), 255 + (2 * yOffset), 0, 255)); EXPECT_PIXEL_COLOR_EQ(245, 240, GLColor(235, 225, 0, 255)); // Again, the "mid-way" coordinates will get values that aren't truly mid-way: EXPECT_PIXEL_COLOR_EQ( xOffset + kCoordMidWayShort, yOffset + kCoordMidWayShort, GLColor(kCoordMidWayShort + (2 * xOffset), kCoordMidWayShort + (2 * yOffset), 0, 255)); EXPECT_PIXEL_COLOR_EQ( xOffset + kCoordMidWayShort, yOffset + kCoordMidWayLong, GLColor(kCoordMidWayShort + (2 * xOffset), kCoordMidWayLong + (2 * yOffset), 0, 255)); EXPECT_PIXEL_COLOR_EQ( xOffset + kCoordMidWayLong, yOffset + kCoordMidWayShort, GLColor(kCoordMidWayLong + (2 * xOffset), kCoordMidWayShort + (2 * yOffset), 0, 255)); EXPECT_PIXEL_COLOR_EQ( xOffset + kCoordMidWayLong, yOffset + kCoordMidWayLong, GLColor(kCoordMidWayLong + (2 * xOffset), kCoordMidWayLong + (2 * yOffset), 0, 255)); // Almost Red EXPECT_PIXEL_COLOR_EQ(255, -yOffset, GLColor(255 + xOffset, 0, 0, 255)); // Almost Green EXPECT_PIXEL_COLOR_EQ(-xOffset, 255, GLColor(0, 255 + yOffset, 0, 255)); // Almost Yellow EXPECT_PIXEL_COLOR_EQ(255, 255, GLColor(255 + xOffset, 255 + yOffset, 0, 255)); ASSERT_GL_NO_ERROR(); ASSERT_EGL_SUCCESS(); } // Draw a predictable pattern (for testing pre-rotation) into a 256x256 portion of the 400x300 // window, and then use glBlitFramebuffer to blit that pattern into an FBO, but with coordinates // that are partially out-of-bounds of the source, and cause a "stretch" to occur TEST_P(EGLPreRotationBlitFramebufferTest, FboDestOutOfBoundsSourceWithStretchBlitFramebuffer) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); // Init program GLuint program = createProgram(); ASSERT_NE(0u, program); glUseProgram(program); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffers[2]; initializeGeometry(program, &indexBuffer, &vertexArray, vertexBuffers); ASSERT_GL_NO_ERROR(); // Create a texture-backed FBO and render the predictable pattern to it GLFramebuffer fbo; GLTexture texture; initializeFBO(&fbo, &texture); ASSERT_GL_NO_ERROR(); glViewport(0, 0, mSize, mSize); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); ASSERT_GL_NO_ERROR(); // Ensure the predictable pattern seems correct in the FBO test256x256PredictablePattern(0, 0); ASSERT_GL_NO_ERROR(); // Prepare to blit to the default framebuffer and read from the FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Blit to the origin of the 400x300 window GLint xOffset = 0; GLint yOffset = 0; // // Test blitting a 256x256 part of the default framebuffer to the entire FBO (no scaling) // // To get the entire predictable pattern into the default framebuffer at the desired offset, // blit it from the FBO glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glViewport(xOffset, yOffset, mSize, mSize); glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Swap buffers to put the image in the window (so the test can be visually checked) eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); // Blit again to check the colors in the back buffer glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Clear the FBO to black and blit from the window to the FBO, but give source coordinates that // are partially outside of the window, but "stretch" the result by 0.5 (i.e. 2X shrink in x) xOffset = -10; yOffset = -15; glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); glViewport(0, 0, mSize, mSize); glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(xOffset, yOffset, xOffset + mSize, yOffset + mSize, 0, 0, mSize / 2, mSize, GL_COLOR_BUFFER_BIT, GL_LINEAR); // Ensure the predictable pattern seems correct in the FBO glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); // NOTE: There is a strip of black on the left and bottom edges of the PBO, corresponding to // the source coordinates that were outside of the source. The strip of black is xOffset/2 // pixels wide on the left side, and yOffset pixels tall on the bottom side. EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor::black, 1); EXPECT_PIXEL_COLOR_NEAR(0, 255, GLColor::black, 1); EXPECT_PIXEL_COLOR_NEAR((-xOffset / 2) - 1, 0, GLColor::black, 1); EXPECT_PIXEL_COLOR_NEAR((-xOffset / 2) - 1, 255, GLColor::black, 1); EXPECT_PIXEL_COLOR_NEAR(0, -yOffset - 1, GLColor::black, 1); EXPECT_PIXEL_COLOR_NEAR(255 / 2, -yOffset - 1, GLColor::black, 1); EXPECT_PIXEL_COLOR_NEAR((255 + xOffset) / 2, 0, GLColor::black, 1); EXPECT_PIXEL_COLOR_NEAR((255 + xOffset) / 2, -yOffset - 1, GLColor::black, 1); EXPECT_PIXEL_COLOR_NEAR(0, 255 + yOffset, GLColor::black, 1); EXPECT_PIXEL_COLOR_NEAR((-xOffset / 2) - 1, 255 + yOffset, GLColor::black, 1); // FBO coordinate (-xOffset, -yOffset) (or (10, 15)) has the values from the bottom-left corner // of the source (which happens to be black). Thus, the following two tests are equivalent: EXPECT_PIXEL_COLOR_NEAR(-xOffset / 2, -yOffset, GLColor::black, 1); EXPECT_PIXEL_COLOR_NEAR(10 + xOffset, 15 + yOffset, GLColor::black, 1); EXPECT_PIXEL_COLOR_NEAR(220 / 2, 215, GLColor(210, 200, 0, 255), 1); EXPECT_PIXEL_COLOR_NEAR((254 + xOffset) / 2, 255 + yOffset, GLColor(254 + (2 * xOffset), 255 + (2 * yOffset), 0, 255), 1); EXPECT_PIXEL_COLOR_NEAR(254 / 2, 240, GLColor(244, 225, 0, 255), 1); // Almost Red EXPECT_PIXEL_COLOR_NEAR(254 / 2, -yOffset, GLColor(254 + xOffset, 0, 0, 255), 1); // Almost Green EXPECT_PIXEL_COLOR_NEAR(-xOffset / 2, 255, GLColor(0, 255 + yOffset, 0, 255), 1); // Almost Yellow EXPECT_PIXEL_COLOR_NEAR(254 / 2, 255, GLColor(254 + xOffset, 255 + yOffset, 0, 255), 1); ASSERT_GL_NO_ERROR(); ASSERT_EGL_SUCCESS(); } // Draw a predictable pattern (for testing pre-rotation) into a 256x256 portion of the 400x300 // window, and then use glBlitFramebuffer to blit that pattern into an FBO, but with source and FBO // coordinates that are partially out-of-bounds of the source TEST_P(EGLPreRotationBlitFramebufferTest, FboDestOutOfBoundsSourceAndDestBlitFramebuffer) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); // Init program GLuint program = createProgram(); ASSERT_NE(0u, program); glUseProgram(program); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffers[2]; initializeGeometry(program, &indexBuffer, &vertexArray, vertexBuffers); ASSERT_GL_NO_ERROR(); // Create a texture-backed FBO and render the predictable pattern to it GLFramebuffer fbo; GLTexture texture; initializeFBO(&fbo, &texture); ASSERT_GL_NO_ERROR(); glViewport(0, 0, mSize, mSize); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); ASSERT_GL_NO_ERROR(); // Ensure the predictable pattern seems correct in the FBO test256x256PredictablePattern(0, 0); ASSERT_GL_NO_ERROR(); // Prepare to blit to the default framebuffer and read from the FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Blit to the origin of the 400x300 window GLint xOffset = 0; GLint yOffset = 0; // // Test blitting a 256x256 part of the default framebuffer to the entire FBO (no scaling) // // To get the entire predictable pattern into the default framebuffer at the desired offset, // blit it from the FBO glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glViewport(xOffset, yOffset, mSize, mSize); glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Swap buffers to put the image in the window (so the test can be visually checked) eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_GL_NO_ERROR(); // Blit again to check the colors in the back buffer glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(0, 0, mSize, mSize, xOffset, yOffset, xOffset + mSize, yOffset + mSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); // Clear the FBO to black and blit from the window to the FBO, but give source coordinates that // are partially outside of the window, and give destination coordinates that are partially // outside of the FBO xOffset = -10; yOffset = -15; glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); glViewport(0, 0, mSize, mSize); glClear(GL_COLOR_BUFFER_BIT); glBlitFramebuffer(xOffset, yOffset, (2 * xOffset) + mSize, (2 * yOffset) + mSize, -xOffset, -yOffset, mSize, mSize, GL_COLOR_BUFFER_BIT, GL_LINEAR); // Ensure the predictable pattern seems correct in the FBO glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); // NOTE: There is a strip of black on the left and bottom edges of the PBO, corresponding to // the source coordinates that were outside of the source. The strip of black is xOffset*2 // pixels wide on the left side, and yOffset*2 pixels tall on the bottom side. EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); EXPECT_PIXEL_COLOR_EQ(0, 255, GLColor::black); EXPECT_PIXEL_COLOR_EQ((-xOffset * 2) - 1, 0, GLColor::black); EXPECT_PIXEL_COLOR_EQ((-xOffset * 2) - 1, 255, GLColor::black); EXPECT_PIXEL_COLOR_EQ(0, (-yOffset * 2) - 1, GLColor::black); EXPECT_PIXEL_COLOR_EQ(255, (-yOffset * 2) - 1, GLColor::black); EXPECT_PIXEL_COLOR_EQ(255 + xOffset, 0, GLColor::black); EXPECT_PIXEL_COLOR_EQ(255 + xOffset, (-yOffset * 2) - 1, GLColor::black); EXPECT_PIXEL_COLOR_EQ(0, 255 + yOffset, GLColor::black); EXPECT_PIXEL_COLOR_EQ((-xOffset * 2) - 1, 255 + yOffset, GLColor::black); // FBO coordinate (-xOffset*2, -yOffset*2) (or (20, 30)) has the values from the bottom-left // corner of the source (which happens to be black). Thus, the following two tests are // equivalent: EXPECT_PIXEL_COLOR_EQ((-xOffset * 2), (-yOffset * 2), GLColor::black); EXPECT_PIXEL_COLOR_EQ(20, 30, GLColor::black); // Note: the following is equivalent to (0, 0): EXPECT_PIXEL_COLOR_EQ(20 + (xOffset * 2), 30 + (yOffset * 2), GLColor::black); EXPECT_PIXEL_COLOR_EQ((-xOffset * 2) + 1, (-yOffset * 2) + 1, GLColor(1, 1, 0, 255)); EXPECT_PIXEL_COLOR_EQ((-xOffset * 2) + 10, (-yOffset * 2) + 10, GLColor(10, 10, 0, 255)); EXPECT_PIXEL_COLOR_EQ((-xOffset * 2) + 20, (-yOffset * 2) + 20, GLColor(20, 20, 0, 255)); EXPECT_PIXEL_COLOR_EQ((-xOffset * 2) + 100, (-yOffset * 2) + 100, GLColor(100, 100, 0, 255)); EXPECT_PIXEL_COLOR_EQ((-xOffset * 2) + 200, (-yOffset * 2) + 200, GLColor(200, 200, 0, 255)); EXPECT_PIXEL_COLOR_EQ((-xOffset * 2) + 230, (-yOffset * 2) + 225, GLColor(230, 225, 0, 255)); // Almost Red EXPECT_PIXEL_COLOR_EQ(255, -yOffset * 2, GLColor(255 + (xOffset * 2), 0, 0, 255)); // Almost Green EXPECT_PIXEL_COLOR_EQ(-xOffset * 2, 255, GLColor(0, 255 + (yOffset * 2), 0, 255)); // Almost Yellow EXPECT_PIXEL_COLOR_EQ(255, 255, GLColor(255 + (xOffset * 2), 255 + (yOffset * 2), 0, 255)); ASSERT_GL_NO_ERROR(); ASSERT_EGL_SUCCESS(); } class EGLPreRotationInterpolateAtOffsetTest : public EGLPreRotationSurfaceTest { protected: EGLPreRotationInterpolateAtOffsetTest() {} GLuint createProgram() { // Init program constexpr char kVS[] = "#version 310 es\n" "#extension GL_OES_shader_multisample_interpolation : require\n" "in highp vec2 position;\n" "uniform float screen_width;\n" "uniform float screen_height;\n" "out highp vec2 v_screenPosition;\n" "out highp vec2 v_offset;\n" "void main (void)\n" "{\n" " gl_Position = vec4(position, 0, 1);\n" " v_screenPosition = (position.xy + vec2(1.0, 1.0)) / 2.0 * vec2(screen_width, " "screen_height);\n" " v_offset = position.xy * 0.5f;\n" "}"; constexpr char kFS[] = "#version 310 es\n" "#extension GL_OES_shader_multisample_interpolation : require\n" "in highp vec2 v_screenPosition;\n" "in highp vec2 v_offset;\n" "layout(location = 0) out mediump vec4 FragColor;\n" "void main() {\n" " const highp float threshold = 0.15625; // 4 subpixel bits. Assume 3 accurate bits " "+ 0.03125 for other errors\n" "\n" " highp vec2 pixelCenter = floor(v_screenPosition) + vec2(0.5, 0.5);\n" " highp vec2 offsetValue = interpolateAtOffset(v_screenPosition, v_offset);\n" " highp vec2 refValue = pixelCenter + v_offset;\n" "\n" " bool valuesEqual = all(lessThan(abs(offsetValue - refValue), vec2(threshold)));\n" " if (valuesEqual)\n" " FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" " else\n" " FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" "}"; return CompileProgram(kVS, kFS); } void initializeGeometry(GLuint program, GLBuffer *indexBuffer, GLVertexArray *vertexArray, GLBuffer *vertexBuffers) { GLint positionLocation = glGetAttribLocation(program, "position"); ASSERT_NE(-1, positionLocation); GLuint screenWidthId = glGetUniformLocation(program, "screen_width"); GLuint screenHeightId = glGetUniformLocation(program, "screen_height"); glUniform1f(screenWidthId, (GLfloat)mSize); glUniform1f(screenHeightId, (GLfloat)mSize); glBindVertexArray(*vertexArray); std::vector indices = {0, 1, 2, 2, 3, 0}; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indices.size(), &indices[0], GL_STATIC_DRAW); std::vector positionData = {// quad vertices -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f}; glBindBuffer(GL_ARRAY_BUFFER, vertexBuffers[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0], GL_STATIC_DRAW); glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr); glEnableVertexAttribArray(positionLocation); } }; // Draw with interpolateAtOffset() builtin function to pre-rotated default FBO TEST_P(EGLPreRotationInterpolateAtOffsetTest, InterpolateAtOffsetWithDefaultFBO) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_shader_multisample_interpolation")); // Init program GLuint program = createProgram(); ASSERT_NE(0u, program); glUseProgram(program); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffers; initializeGeometry(program, &indexBuffer, &vertexArray, &vertexBuffers); ASSERT_GL_NO_ERROR(); glViewport(0, 0, mSize, mSize); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(0, 255, 0, 255)); EXPECT_PIXEL_COLOR_EQ(mSize - 1, 0, GLColor(0, 255, 0, 255)); EXPECT_PIXEL_COLOR_EQ(0, mSize - 1, GLColor(0, 255, 0, 255)); EXPECT_PIXEL_COLOR_EQ(mSize - 1, mSize - 1, GLColor(0, 255, 0, 255)); ASSERT_GL_NO_ERROR(); // Make the image visible eglSwapBuffers(mDisplay, mWindowSurface); ASSERT_EGL_SUCCESS(); } // Draw with interpolateAtOffset() builtin function to pre-rotated custom FBO TEST_P(EGLPreRotationInterpolateAtOffsetTest, InterpolateAtOffsetWithCustomFBO) { // http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(isVulkanRenderer() && IsLinux() && IsIntel()); // Flaky on Linux SwANGLE http://anglebug.com/4453 ANGLE_SKIP_TEST_IF(IsLinux() && isSwiftshader()); // To aid in debugging, we want this window visible setWindowVisible(mOSWindow, true); initializeDisplay(); initializeSurfaceWithRGBA8888Config(); eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext); ASSERT_EGL_SUCCESS(); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_shader_multisample_interpolation")); // Init program GLuint program = createProgram(); ASSERT_NE(0u, program); glUseProgram(program); GLBuffer indexBuffer; GLVertexArray vertexArray; GLBuffer vertexBuffers; initializeGeometry(program, &indexBuffer, &vertexArray, &vertexBuffers); ASSERT_GL_NO_ERROR(); // Create a texture-backed FBO GLFramebuffer fbo; GLTexture texture; glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mSize, mSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); ASSERT_GL_NO_ERROR(); glViewport(0, 0, mSize, mSize); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(0, 255, 0, 255)); EXPECT_PIXEL_COLOR_EQ(mSize - 1, 0, GLColor(0, 255, 0, 255)); EXPECT_PIXEL_COLOR_EQ(0, mSize - 1, GLColor(0, 255, 0, 255)); EXPECT_PIXEL_COLOR_EQ(mSize - 1, mSize - 1, GLColor(0, 255, 0, 255)); ASSERT_GL_NO_ERROR(); } } // anonymous namespace #ifdef Bool // X11 ridiculousness. # undef Bool #endif GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLPreRotationInterpolateAtOffsetTest); ANGLE_INSTANTIATE_TEST_COMBINE_1(EGLPreRotationInterpolateAtOffsetTest, PrintToStringParamName, testing::Bool(), WithNoFixture(ES31_VULKAN())); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLPreRotationSurfaceTest); ANGLE_INSTANTIATE_TEST_COMBINE_1(EGLPreRotationSurfaceTest, PrintToStringParamName, testing::Bool(), WithNoFixture(ES2_VULKAN()), WithNoFixture(ES3_VULKAN()), WithNoFixture(ES3_VULKAN_SWIFTSHADER())); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLPreRotationLargeSurfaceTest); ANGLE_INSTANTIATE_TEST_COMBINE_1(EGLPreRotationLargeSurfaceTest, PrintToStringParamName, testing::Bool(), WithNoFixture(ES2_VULKAN()), WithNoFixture(ES3_VULKAN()), WithNoFixture(ES3_VULKAN_SWIFTSHADER())); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLPreRotationBlitFramebufferTest); ANGLE_INSTANTIATE_TEST_COMBINE_1(EGLPreRotationBlitFramebufferTest, PrintToStringParamName, testing::Bool(), WithNoFixture(ES2_VULKAN()), WithNoFixture(ES3_VULKAN()), WithNoFixture(ES3_VULKAN_SWIFTSHADER()));