/*------------------------------------------------------------------------- * drawElements Quality Program EGL Module * --------------------------------------- * * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Test KHR_swap_buffer_with_damage *//*--------------------------------------------------------------------*/ #include "teglSwapBuffersWithDamageTests.hpp" #include "tcuImageCompare.hpp" #include "tcuSurface.hpp" #include "tcuTextureUtil.hpp" #include "egluNativeWindow.hpp" #include "egluUtil.hpp" #include "egluConfigFilter.hpp" #include "eglwLibrary.hpp" #include "eglwEnums.hpp" #include "gluDefs.hpp" #include "gluRenderContext.hpp" #include "gluShaderProgram.hpp" #include "glwDefs.hpp" #include "glwEnums.hpp" #include "glwFunctions.hpp" #include "deRandom.hpp" #include "deString.h" #include #include #include using glw::GLubyte; using std::string; using std::vector; using tcu::IVec2; using namespace eglw; namespace deqp { namespace egl { namespace { typedef tcu::Vector Color; enum DrawType { DRAWTYPE_GLES2_CLEAR, DRAWTYPE_GLES2_RENDER }; enum ResizeType { RESIZETYPE_NONE = 0, RESIZETYPE_BEFORE_SWAP, RESIZETYPE_AFTER_SWAP, RESIZETYPE_LAST }; struct ColoredRect { public: ColoredRect(const IVec2 &bottomLeft_, const IVec2 &topRight_, const Color &color_); IVec2 bottomLeft; IVec2 topRight; Color color; }; ColoredRect::ColoredRect(const IVec2 &bottomLeft_, const IVec2 &topRight_, const Color &color_) : bottomLeft(bottomLeft_) , topRight(topRight_) , color(color_) { } struct DrawCommand { DrawCommand(DrawType drawType_, const ColoredRect &rect_); DrawType drawType; ColoredRect rect; }; DrawCommand::DrawCommand(DrawType drawType_, const ColoredRect &rect_) : drawType(drawType_), rect(rect_) { } struct Frame { Frame(int width_, int height_); int width; int height; vector draws; }; Frame::Frame(int width_, int height_) : width(width_), height(height_) { } typedef vector FrameSequence; //helper function declaration EGLConfig getEGLConfig(const Library &egl, EGLDisplay eglDisplay, bool preserveBuffer); void clearColorScreen(const glw::Functions &gl, const tcu::Vec4 &clearColor); float windowToDeviceCoordinates(int x, int length); class GLES2Renderer { public: GLES2Renderer(const glw::Functions &gl); ~GLES2Renderer(void); void render(int width, int height, const Frame &frame) const; private: GLES2Renderer(const GLES2Renderer &); GLES2Renderer &operator=(const GLES2Renderer &); const glw::Functions &m_gl; glu::ShaderProgram m_glProgram; glw::GLuint m_coordLoc; glw::GLuint m_colorLoc; }; // generate sources for vertex and fragment buffer glu::ProgramSources getSources(void) { const char *const vertexShaderSource = "attribute mediump vec2 a_pos;\n" "attribute mediump vec4 a_color;\n" "varying mediump vec4 v_color;\n" "void main(void)\n" "{\n" "\tv_color = a_color;\n" "\tgl_Position = vec4(a_pos, 0.0, 1.0);\n" "}"; const char *const fragmentShaderSource = "varying mediump vec4 v_color;\n" "void main(void)\n" "{\n" "\tgl_FragColor = v_color;\n" "}"; return glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource); } GLES2Renderer::GLES2Renderer(const glw::Functions &gl) : m_gl(gl) , m_glProgram(gl, getSources()) , m_coordLoc((glw::GLuint)-1) , m_colorLoc((glw::GLuint)-1) { m_colorLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_color"); m_coordLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_pos"); GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to get attribute locations"); } GLES2Renderer::~GLES2Renderer(void) { } void GLES2Renderer::render(int width, int height, const Frame &frame) const { for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++) { const ColoredRect &coloredRect = frame.draws[drawNdx].rect; if (frame.draws[drawNdx].drawType == DRAWTYPE_GLES2_RENDER) { const float x1 = windowToDeviceCoordinates(coloredRect.bottomLeft.x(), width); const float y1 = windowToDeviceCoordinates(coloredRect.bottomLeft.y(), height); const float x2 = windowToDeviceCoordinates(coloredRect.topRight.x(), width); const float y2 = windowToDeviceCoordinates(coloredRect.topRight.y(), height); const glw::GLfloat coords[] = { x1, y1, x1, y2, x2, y2, x2, y2, x2, y1, x1, y1, }; const glw::GLubyte colors[] = { coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255, coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255, coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255, coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255, coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255, coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255, }; m_gl.useProgram(m_glProgram.getProgram()); GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed"); m_gl.enableVertexAttribArray(m_coordLoc); m_gl.enableVertexAttribArray(m_colorLoc); GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to enable attributes"); m_gl.vertexAttribPointer(m_coordLoc, 2, GL_FLOAT, GL_FALSE, 0, coords); m_gl.vertexAttribPointer(m_colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors); GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to set attribute pointers"); m_gl.drawArrays(GL_TRIANGLES, 0, DE_LENGTH_OF_ARRAY(coords) / 2); GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays(), failed"); m_gl.disableVertexAttribArray(m_coordLoc); m_gl.disableVertexAttribArray(m_colorLoc); GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to disable attributes"); m_gl.useProgram(0); GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed"); } else if (frame.draws[drawNdx].drawType == DRAWTYPE_GLES2_CLEAR) { m_gl.enable(GL_SCISSOR_TEST); m_gl.scissor(coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(), coloredRect.topRight.x() - coloredRect.bottomLeft.x(), coloredRect.topRight.y() - coloredRect.bottomLeft.y()); m_gl.clearColor(coloredRect.color.x() / 255.0f, coloredRect.color.y() / 255.0f, coloredRect.color.z() / 255.0f, 1.0f); m_gl.clear(GL_COLOR_BUFFER_BIT); m_gl.disable(GL_SCISSOR_TEST); } else DE_FATAL("Invalid drawtype"); } } class SwapBuffersWithDamageTest : public TestCase { public: SwapBuffersWithDamageTest(EglTestContext &eglTestCtx, const vector &frameDrawType, int iterationTimes, ResizeType resizeType, const char *name, const char *description); ~SwapBuffersWithDamageTest(void); virtual void init(void); void deinit(void); virtual IterateResult iterate(void); protected: virtual EGLConfig getConfig(const Library &egl, EGLDisplay eglDisplay); virtual void checkExtension(const Library &egl, EGLDisplay eglDisplay); void initEGLSurface(EGLConfig config); void initEGLContext(EGLConfig config); eglu::NativeWindow *m_window; EGLConfig m_eglConfig; EGLContext m_eglContext; const int m_seed; const int m_iterationTimes; const vector m_frameDrawType; const ResizeType m_resizeType; EGLDisplay m_eglDisplay; EGLSurface m_eglSurface; glw::Functions m_gl; GLES2Renderer *m_gles2Renderer; }; SwapBuffersWithDamageTest::SwapBuffersWithDamageTest(EglTestContext &eglTestCtx, const vector &frameDrawType, int iterationTimes, ResizeType resizeType, const char *name, const char *description) : TestCase(eglTestCtx, name, description) , m_window(DE_NULL) , m_eglContext(EGL_NO_CONTEXT) , m_seed(deStringHash(name)) , m_iterationTimes(iterationTimes) , m_frameDrawType(frameDrawType) , m_resizeType(resizeType) , m_eglDisplay(EGL_NO_DISPLAY) , m_eglSurface(EGL_NO_SURFACE) , m_gles2Renderer(DE_NULL) { } SwapBuffersWithDamageTest::~SwapBuffersWithDamageTest(void) { deinit(); } EGLConfig SwapBuffersWithDamageTest::getConfig(const Library &egl, EGLDisplay eglDisplay) { return getEGLConfig(egl, eglDisplay, false); } void SwapBuffersWithDamageTest::checkExtension(const Library &egl, EGLDisplay eglDisplay) { if (!eglu::hasExtension(egl, eglDisplay, "EGL_KHR_swap_buffers_with_damage")) TCU_THROW(NotSupportedError, "EGL_KHR_swap_buffers_with_damage is not supported"); } void SwapBuffersWithDamageTest::init(void) { const Library &egl = m_eglTestCtx.getLibrary(); m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()); m_eglConfig = getConfig(egl, m_eglDisplay); checkExtension(egl, m_eglDisplay); initEGLSurface(m_eglConfig); initEGLContext(m_eglConfig); m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2, 0)); m_gles2Renderer = new GLES2Renderer(m_gl); } void SwapBuffersWithDamageTest::deinit(void) { const Library &egl = m_eglTestCtx.getLibrary(); delete m_gles2Renderer; m_gles2Renderer = DE_NULL; if (m_eglContext != EGL_NO_CONTEXT) { egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); egl.destroyContext(m_eglDisplay, m_eglContext); m_eglContext = EGL_NO_CONTEXT; } if (m_eglSurface != EGL_NO_SURFACE) { egl.destroySurface(m_eglDisplay, m_eglSurface); m_eglSurface = EGL_NO_SURFACE; } if (m_eglDisplay != EGL_NO_DISPLAY) { egl.terminate(m_eglDisplay); m_eglDisplay = EGL_NO_DISPLAY; } delete m_window; m_window = DE_NULL; } void SwapBuffersWithDamageTest::initEGLSurface(EGLConfig config) { const eglu::NativeWindowFactory &factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine()); m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL, eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine()))); m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL); } void SwapBuffersWithDamageTest::initEGLContext(EGLConfig config) { const Library &egl = m_eglTestCtx.getLibrary(); const EGLint attribList[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; egl.bindAPI(EGL_OPENGL_ES_API); m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList); EGLU_CHECK_MSG(egl, "eglCreateContext"); TCU_CHECK(m_eglSurface != EGL_NO_SURFACE); egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext); EGLU_CHECK_MSG(egl, "eglMakeCurrent"); } FrameSequence generateFrameSequence(const vector &frameDrawType, de::Random &rnd, int numFrames, int width, int height); vector getDamageRegion(const Frame &frame); TestCase::IterateResult SwapBuffersWithDamageTest::iterate(void) { de::Random rnd(m_seed); const Library &egl = m_eglTestCtx.getLibrary(); const int width = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH); const int height = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT); const float clearRed = rnd.getFloat(); const float clearGreen = rnd.getFloat(); const float clearBlue = rnd.getFloat(); const tcu::Vec4 clearColor(clearRed, clearGreen, clearBlue, 1.0f); const int numFrames = 24; // (width, height) = (480, 480) --> numFrame = 24, divisible const FrameSequence frameSequence = generateFrameSequence(m_frameDrawType, rnd, numFrames, width, height); m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED)); for (int iterationNdx = 0; iterationNdx < m_iterationTimes; iterationNdx++) { for (int currentFrameNdx = 0; currentFrameNdx < numFrames; currentFrameNdx++) { vector damageRegion = getDamageRegion(frameSequence[currentFrameNdx]); clearColorScreen(m_gl, clearColor); for (int ndx = 0; ndx <= currentFrameNdx; ndx++) m_gles2Renderer->render(width, height, frameSequence[ndx]); if (m_resizeType == RESIZETYPE_BEFORE_SWAP) { if (currentFrameNdx % 2 == 0) m_window->setSurfaceSize(IVec2(width * 2, height / 2)); else m_window->setSurfaceSize(IVec2(height / 2, width * 2)); } EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size() / 4)); if (m_resizeType == RESIZETYPE_AFTER_SWAP) { if (currentFrameNdx % 2 == 0) m_window->setSurfaceSize(IVec2(width * 2, height / 2)); else m_window->setSurfaceSize(IVec2(height / 2, width * 2)); } } } return STOP; } class SwapBuffersWithDamageAndPreserveBufferTest : public SwapBuffersWithDamageTest { public: SwapBuffersWithDamageAndPreserveBufferTest(EglTestContext &eglTestCtx, const vector &frameDrawType, int iterationTimes, ResizeType resizeType, const char *name, const char *description); IterateResult iterate(void); protected: EGLConfig getConfig(const Library &egl, EGLDisplay eglDisplay); }; SwapBuffersWithDamageAndPreserveBufferTest::SwapBuffersWithDamageAndPreserveBufferTest( EglTestContext &eglTestCtx, const vector &frameDrawType, int iterationTimes, ResizeType resizeType, const char *name, const char *description) : SwapBuffersWithDamageTest(eglTestCtx, frameDrawType, iterationTimes, resizeType, name, description) { } EGLConfig SwapBuffersWithDamageAndPreserveBufferTest::getConfig(const Library &egl, EGLDisplay eglDisplay) { return getEGLConfig(egl, eglDisplay, true); } TestCase::IterateResult SwapBuffersWithDamageAndPreserveBufferTest::iterate(void) { de::Random rnd(m_seed); const Library &egl = m_eglTestCtx.getLibrary(); const int width = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH); const int height = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT); const float clearRed = rnd.getFloat(); const float clearGreen = rnd.getFloat(); const float clearBlue = rnd.getFloat(); const tcu::Vec4 clearColor(clearRed, clearGreen, clearBlue, 1.0f); const int numFrames = 24; // (width, height) = (480, 480) --> numFrame = 24, divisible const FrameSequence frameSequence = generateFrameSequence(m_frameDrawType, rnd, numFrames, width, height); m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED)); for (int iterationNdx = 0; iterationNdx < m_iterationTimes; iterationNdx++) { clearColorScreen(m_gl, clearColor); EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, DE_NULL, 0)); for (int frameNdx = 0; frameNdx < numFrames; frameNdx++) { const Frame ¤tFrame = frameSequence[frameNdx]; vector damageRegion = getDamageRegion(currentFrame); m_gles2Renderer->render(width, height, currentFrame); if (m_resizeType == RESIZETYPE_BEFORE_SWAP) { if (frameNdx % 2 == 0) m_window->setSurfaceSize(IVec2(width * 2, height / 2)); else m_window->setSurfaceSize(IVec2(height / 2, width * 2)); } EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size() / 4)); if (m_resizeType == RESIZETYPE_AFTER_SWAP) { if (frameNdx % 2 == 0) m_window->setSurfaceSize(IVec2(width * 2, height / 2)); else m_window->setSurfaceSize(IVec2(height / 2, width * 2)); } } } return STOP; } class SwapBuffersWithDamageAndBufferAgeTest : public SwapBuffersWithDamageTest { public: SwapBuffersWithDamageAndBufferAgeTest(EglTestContext &eglTestCtx, const vector &frameDrawType, int iterationTimes, ResizeType resizeType, const char *name, const char *description); IterateResult iterate(void); protected: void checkExtension(const Library &egl, EGLDisplay eglDisplay); }; SwapBuffersWithDamageAndBufferAgeTest::SwapBuffersWithDamageAndBufferAgeTest(EglTestContext &eglTestCtx, const vector &frameDrawType, int iterationTimes, ResizeType resizeType, const char *name, const char *description) : SwapBuffersWithDamageTest(eglTestCtx, frameDrawType, iterationTimes, resizeType, name, description) { } void SwapBuffersWithDamageAndBufferAgeTest::checkExtension(const Library &egl, EGLDisplay eglDisplay) { if (!eglu::hasExtension(egl, eglDisplay, "EGL_KHR_swap_buffers_with_damage")) TCU_THROW(NotSupportedError, "EGL_KHR_swap_buffers_with_damage is not supported"); if (!eglu::hasExtension(egl, eglDisplay, "EGL_EXT_buffer_age")) TCU_THROW(NotSupportedError, "EGL_EXT_buffer_age not supported"); } TestCase::IterateResult SwapBuffersWithDamageAndBufferAgeTest::iterate(void) { de::Random rnd(m_seed); const Library &egl = m_eglTestCtx.getLibrary(); const int width = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH); const int height = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT); const float clearRed = rnd.getFloat(); const float clearGreen = rnd.getFloat(); const float clearBlue = rnd.getFloat(); const tcu::Vec4 clearColor(clearRed, clearGreen, clearBlue, 1.0f); const int numFrames = 24; // (width, height) = (480, 480) --> numFrame = 24, divisible const FrameSequence frameSequence = generateFrameSequence(m_frameDrawType, rnd, numFrames, width, height); m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED)); for (int iterationNdx = 0; iterationNdx < m_iterationTimes; iterationNdx++) { clearColorScreen(m_gl, clearColor); EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, DE_NULL, 0)); for (int frameNdx = 0; frameNdx < numFrames; frameNdx++) { vector damageRegion; int bufferAge = -1; int startFrameNdx = -1; int endFrameNdx = frameNdx; EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_EXT, &bufferAge)); if (bufferAge < 0) // invalid buffer age { std::ostringstream stream; stream << "Fail, the age is invalid. Age: " << bufferAge << ", frameNdx: " << frameNdx; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str()); return STOP; } if (bufferAge == 0 || bufferAge > frameNdx) { clearColorScreen(m_gl, clearColor); startFrameNdx = 0; } else startFrameNdx = frameNdx - bufferAge + 1; for (int ndx = startFrameNdx; ndx <= endFrameNdx; ndx++) { const vector partialDamageRegion = getDamageRegion(frameSequence[ndx]); damageRegion.insert(damageRegion.end(), partialDamageRegion.begin(), partialDamageRegion.end()); m_gles2Renderer->render(width, height, frameSequence[ndx]); } if (m_resizeType == RESIZETYPE_BEFORE_SWAP) { if (frameNdx % 2 == 0) m_window->setSurfaceSize(IVec2(width * 2, height / 2)); else m_window->setSurfaceSize(IVec2(height / 2, width * 2)); } EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size() / 4)); if (m_resizeType == RESIZETYPE_AFTER_SWAP) { if (frameNdx % 2 == 0) m_window->setSurfaceSize(IVec2(width * 2, height / 2)); else m_window->setSurfaceSize(IVec2(height / 2, width * 2)); } } } return STOP; } // generate a frame sequence with certain frame for visual verification FrameSequence generateFrameSequence(const vector &frameDrawType, de::Random &rnd, int numFrames, int width, int height) { const int frameDiff = height / numFrames; const GLubyte r = rnd.getUint8(); const GLubyte g = rnd.getUint8(); const GLubyte b = rnd.getUint8(); const Color color(r, g, b); FrameSequence frameSequence; for (int frameNdx = 0; frameNdx < numFrames; frameNdx++) { Frame frame(width, height); for (int rectNdx = 0; rectNdx < (int)frameDrawType.size(); rectNdx++) { const int rectHeight = frameDiff / (int)frameDrawType.size(); const ColoredRect rect(IVec2(0, frameNdx * frameDiff + rectNdx * rectHeight), IVec2(width, frameNdx * frameDiff + (rectNdx + 1) * rectHeight), color); const DrawCommand drawCommand(frameDrawType[rectNdx], rect); frame.draws.push_back(drawCommand); } frameSequence.push_back(frame); } return frameSequence; } vector getDamageRegion(const Frame &frame) { vector damageRegion; for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++) { const ColoredRect &rect = frame.draws[drawNdx].rect; damageRegion.push_back(rect.bottomLeft.x()); damageRegion.push_back(rect.bottomLeft.y()); damageRegion.push_back(rect.topRight.x() - rect.bottomLeft.x()); damageRegion.push_back(rect.topRight.y() - rect.bottomLeft.y()); } DE_ASSERT(damageRegion.size() % 4 == 0); return damageRegion; } string generateTestName(const vector &frameDrawType) { std::ostringstream stream; for (size_t ndx = 0; ndx < frameDrawType.size(); ndx++) { if (frameDrawType[ndx] == DRAWTYPE_GLES2_RENDER) stream << "render"; else if (frameDrawType[ndx] == DRAWTYPE_GLES2_CLEAR) stream << "clear"; else DE_ASSERT(false); if (ndx < frameDrawType.size() - 1) stream << "_"; } return stream.str(); } string generateResizeGroupName(ResizeType resizeType) { switch (resizeType) { case RESIZETYPE_NONE: return "no_resize"; case RESIZETYPE_AFTER_SWAP: return "resize_after_swap"; case RESIZETYPE_BEFORE_SWAP: return "resize_before_swap"; default: DE_FATAL("Unknown resize type"); return ""; } } bool isWindow(const eglu::CandidateConfig &c) { return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT; } bool isES2Renderable(const eglu::CandidateConfig &c) { return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT; } bool hasPreserveSwap(const eglu::CandidateConfig &c) { return (c.surfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == EGL_SWAP_BEHAVIOR_PRESERVED_BIT; } EGLConfig getEGLConfig(const Library &egl, EGLDisplay eglDisplay, bool preserveBuffer) { eglu::FilterList filters; filters << isWindow << isES2Renderable; if (preserveBuffer) filters << hasPreserveSwap; return eglu::chooseSingleConfig(egl, eglDisplay, filters); } void clearColorScreen(const glw::Functions &gl, const tcu::Vec4 &clearColor) { gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w()); gl.clear(GL_COLOR_BUFFER_BIT); } float windowToDeviceCoordinates(int x, int length) { return (2.0f * float(x) / float(length)) - 1.0f; } } // namespace SwapBuffersWithDamageTests::SwapBuffersWithDamageTests(EglTestContext &eglTestCtx) : TestCaseGroup(eglTestCtx, "swap_buffers_with_damage", "Swap buffers with damages tests") { } void SwapBuffersWithDamageTests::init(void) { const DrawType clearRender[2] = {DRAWTYPE_GLES2_CLEAR, DRAWTYPE_GLES2_RENDER}; const DrawType renderClear[2] = {DRAWTYPE_GLES2_RENDER, DRAWTYPE_GLES2_CLEAR}; const ResizeType resizeTypes[] = {RESIZETYPE_NONE, RESIZETYPE_BEFORE_SWAP, RESIZETYPE_AFTER_SWAP}; vector> frameDrawTypes; frameDrawTypes.push_back(vector(1, DRAWTYPE_GLES2_CLEAR)); frameDrawTypes.push_back(vector(1, DRAWTYPE_GLES2_RENDER)); frameDrawTypes.push_back(vector(2, DRAWTYPE_GLES2_CLEAR)); frameDrawTypes.push_back(vector(2, DRAWTYPE_GLES2_RENDER)); frameDrawTypes.push_back(vector(DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender))); frameDrawTypes.push_back(vector(DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear))); for (size_t resizeTypeNdx = 0; resizeTypeNdx < DE_LENGTH_OF_ARRAY(resizeTypes); resizeTypeNdx++) { const ResizeType resizeType = resizeTypes[resizeTypeNdx]; TestCaseGroup *const resizeGroup = new TestCaseGroup(m_eglTestCtx, generateResizeGroupName(resizeType).c_str(), ""); for (size_t drawTypeNdx = 0; drawTypeNdx < frameDrawTypes.size(); drawTypeNdx++) { string name = generateTestName(frameDrawTypes[drawTypeNdx]); resizeGroup->addChild(new SwapBuffersWithDamageTest(m_eglTestCtx, frameDrawTypes[drawTypeNdx], 4, resizeType, name.c_str(), "")); } for (size_t drawTypeNdx = 0; drawTypeNdx < frameDrawTypes.size(); drawTypeNdx++) { string name = "preserve_buffer_" + generateTestName(frameDrawTypes[drawTypeNdx]); resizeGroup->addChild(new SwapBuffersWithDamageAndPreserveBufferTest( m_eglTestCtx, frameDrawTypes[drawTypeNdx], 4, resizeType, name.c_str(), "")); } for (size_t drawTypeNdx = 0; drawTypeNdx < frameDrawTypes.size(); drawTypeNdx++) { string name = "buffer_age_" + generateTestName(frameDrawTypes[drawTypeNdx]); resizeGroup->addChild(new SwapBuffersWithDamageAndBufferAgeTest(m_eglTestCtx, frameDrawTypes[drawTypeNdx], 4, resizeType, name.c_str(), "")); } addChild(resizeGroup); } } } // namespace egl } // namespace deqp