Merge "Add tests for EGL_EXT_buffer_age"
diff --git a/Android.mk b/Android.mk
index 76dc0fb..638ecf2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -246,6 +246,7 @@
framework/referencerenderer/rrVertexPacket.cpp \
modules/egl/teglAndroidUtil.cpp \
modules/egl/teglApiCase.cpp \
+ modules/egl/teglBufferAgeTests.cpp \
modules/egl/teglChooseConfigReference.cpp \
modules/egl/teglChooseConfigTests.cpp \
modules/egl/teglClientExtensionTests.cpp \
diff --git a/modules/egl/CMakeLists.txt b/modules/egl/CMakeLists.txt
index 37a06fd..070487f 100644
--- a/modules/egl/CMakeLists.txt
+++ b/modules/egl/CMakeLists.txt
@@ -5,6 +5,8 @@
teglAndroidUtil.hpp
teglApiCase.cpp
teglApiCase.hpp
+ teglBufferAgeTests.hpp
+ teglBufferAgeTests.cpp
teglChooseConfigReference.cpp
teglChooseConfigReference.hpp
teglChooseConfigTests.cpp
diff --git a/modules/egl/teglBufferAgeTests.cpp b/modules/egl/teglBufferAgeTests.cpp
new file mode 100644
index 0000000..57feb50
--- /dev/null
+++ b/modules/egl/teglBufferAgeTests.cpp
@@ -0,0 +1,692 @@
+/*-------------------------------------------------------------------------
+ * 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 EXT_buffer_age
+ *//*--------------------------------------------------------------------*/
+
+#include "teglBufferAgeTests.hpp"
+
+#include "tcuImageCompare.hpp"
+#include "tcuTestLog.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 <string>
+#include <vector>
+#include <sstream>
+
+using std::string;
+using std::vector;
+using glw::GLubyte;
+using tcu::IVec2;
+
+using namespace eglw;
+
+namespace deqp
+{
+namespace egl
+{
+namespace
+{
+
+typedef tcu::Vector<GLubyte, 3> Color;
+
+class GLES2Renderer;
+
+class ReferenceRenderer;
+
+class BufferAgeTest : public TestCase
+{
+public:
+ enum DrawType
+ {
+ DRAWTYPE_GLES2_CLEAR,
+ DRAWTYPE_GLES2_RENDER
+ };
+
+ BufferAgeTest (EglTestContext& eglTestCtx, bool preserveColorBuffer, const vector<DrawType>& oddFrameDrawType,
+ const vector<DrawType>& evenFrameDrawType, const char* name, const char* description);
+ ~BufferAgeTest (void);
+
+ void init (void);
+ void deinit (void);
+ IterateResult iterate (void);
+
+private:
+ void initEGLSurface (EGLConfig config);
+ void initEGLContext (EGLConfig config);
+
+ const int m_seed;
+ const bool m_preserveColorBuffer;
+ const vector<DrawType> m_oddFrameDrawType;
+ const vector<DrawType> m_evenFrameDrawType;
+
+ EGLDisplay m_eglDisplay;
+ eglu::NativeWindow* m_window;
+ EGLSurface m_eglSurface;
+ EGLConfig m_eglConfig;
+ EGLContext m_eglContext;
+ glw::Functions m_gl;
+
+ GLES2Renderer* m_gles2Renderer;
+ ReferenceRenderer* m_refRenderer;
+
+};
+
+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 (const BufferAgeTest::DrawType drawType_, const ColoredRect& rect_);
+ BufferAgeTest::DrawType drawType;
+ ColoredRect rect;
+};
+
+DrawCommand::DrawCommand (const BufferAgeTest::DrawType drawType_, const ColoredRect& rect_)
+ : drawType(drawType_)
+ , rect (rect_)
+{
+}
+
+struct Frame
+{
+ Frame (int width_, int height_);
+ int width;
+ int height;
+ vector<DrawCommand> draws;
+};
+
+Frame::Frame (int width_, int height_)
+ : width(width_)
+ , height(height_)
+{
+}
+
+
+// (x1,y1) lie in the lower-left quadrant while (x2,y2) lie in the upper-right.
+// the coords are multiplied by 4 to amplify the minimial difference between coords to 4 (if not zero)
+// to avoid the situation where two edges are too close to each other which makes the rounding error
+// intoleratable by compareToReference()
+void generateRandomFrame (Frame* dst, const vector<BufferAgeTest::DrawType>& drawTypes, de::Random& rnd)
+{
+ for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
+ {
+ const int x1 = rnd.getInt(0, (dst->width-1)/8) * 4;
+ const int y1 = rnd.getInt(0, (dst->height-1)/8) * 4;
+ const int x2 = rnd.getInt((dst->width-1)/8, (dst->width-1)/4) * 4;
+ const int y2 = rnd.getInt((dst->height-1)/8, (dst->height-1)/4) * 4;
+ const GLubyte r = rnd.getUint8();
+ const GLubyte g = rnd.getUint8();
+ const GLubyte b = rnd.getUint8();
+ const ColoredRect coloredRect (IVec2(x1, y1), IVec2(x2, y2), Color(r, g, b));
+ const DrawCommand drawCommand (drawTypes[ndx], coloredRect);
+ (*dst).draws.push_back(drawCommand);
+ }
+}
+
+typedef vector<Frame> FrameSequence;
+
+//helper function declaration
+EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay, bool preserveColorBuffer);
+void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor);
+void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor);
+void readPixels (const glw::Functions& gl, tcu::Surface* screen);
+float windowToDeviceCoordinates (int x, int length);
+bool compareToReference (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum);
+vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx);
+
+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 vec4 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 = a_pos;\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 == BufferAgeTest::DRAWTYPE_GLES2_RENDER)
+ {
+ float x1 = windowToDeviceCoordinates(coloredRect.bottomLeft.x(), width);
+ float y1 = windowToDeviceCoordinates(coloredRect.bottomLeft.y(), height);
+ float x2 = windowToDeviceCoordinates(coloredRect.topRight.x(), width);
+ float y2 = windowToDeviceCoordinates(coloredRect.topRight.y(), height);
+
+ const glw::GLfloat coords[] =
+ {
+ x1, y1, 0.0f, 1.0f,
+ x1, y2, 0.0f, 1.0f,
+ x2, y2, 0.0f, 1.0f,
+
+ x2, y2, 0.0f, 1.0f,
+ x2, y1, 0.0f, 1.0f,
+ x1, y1, 0.0f, 1.0f
+ };
+
+ 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, 4, 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)/4);
+ 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 == BufferAgeTest::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_ASSERT(false);
+ }
+}
+
+class ReferenceRenderer
+{
+public:
+ ReferenceRenderer (void);
+ void render (tcu::Surface* target, const Frame& frame) const;
+private:
+ ReferenceRenderer (const ReferenceRenderer&);
+ ReferenceRenderer& operator= (const ReferenceRenderer&);
+};
+
+ReferenceRenderer::ReferenceRenderer(void)
+{
+}
+
+void ReferenceRenderer::render (tcu::Surface* target, 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 == BufferAgeTest::DRAWTYPE_GLES2_RENDER || frame.draws[drawNdx].drawType == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
+ {
+ const tcu::UVec4 color(coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255);
+ tcu::clear(tcu::getSubregion(target->getAccess(), coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
+ coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y()), color);
+ }
+ else
+ DE_ASSERT(false);
+ }
+}
+
+BufferAgeTest::BufferAgeTest (EglTestContext& eglTestCtx, bool preserveColorBuffer, const vector<DrawType>& oddFrameDrawType, const vector<DrawType>& evenFrameDrawType,
+ const char* name, const char* description)
+ : TestCase (eglTestCtx, name, description)
+ , m_seed (deStringHash(name))
+ , m_preserveColorBuffer (preserveColorBuffer)
+ , m_oddFrameDrawType (oddFrameDrawType)
+ , m_evenFrameDrawType (evenFrameDrawType)
+ , m_eglDisplay (EGL_NO_DISPLAY)
+ , m_window (DE_NULL)
+ , m_eglSurface (EGL_NO_SURFACE)
+ , m_eglContext (EGL_NO_CONTEXT)
+ , m_gles2Renderer (DE_NULL)
+ , m_refRenderer (DE_NULL)
+{
+}
+
+BufferAgeTest::~BufferAgeTest (void)
+{
+ deinit();
+}
+
+void BufferAgeTest::init (void)
+{
+ const Library& egl = m_eglTestCtx.getLibrary();
+
+ m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
+ m_eglConfig = getEGLConfig(m_eglTestCtx.getLibrary(), m_eglDisplay, m_preserveColorBuffer);
+
+ if (m_eglConfig == DE_NULL)
+ TCU_THROW(NotSupportedError, "No supported config found");
+
+ //create surface and context and make them current
+ initEGLSurface(m_eglConfig);
+ initEGLContext(m_eglConfig);
+
+ m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
+
+ if (eglu::hasExtension(egl, m_eglDisplay, "EGL_EXT_buffer_age") == false)
+ TCU_THROW(NotSupportedError, "EGL_EXT_buffer_age is not supported");
+
+ m_gles2Renderer = new GLES2Renderer(m_gl);
+ m_refRenderer = new ReferenceRenderer();
+}
+
+void BufferAgeTest::deinit (void)
+{
+ const Library& egl = m_eglTestCtx.getLibrary();
+
+ delete m_refRenderer;
+ m_refRenderer = DE_NULL;
+
+ 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 BufferAgeTest::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 BufferAgeTest::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");
+ DE_ASSERT(m_eglSurface != EGL_NO_SURFACE);
+ egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
+ EGLU_CHECK_MSG(egl, "eglMakeCurrent");
+}
+
+// return indices of frames that have been written to the given buffer
+vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx)
+{
+ DE_ASSERT(frameNdx < (int)bufferAges.size());
+ vector<int> frameOnBuffer;
+ int age = bufferAges[frameNdx];
+ while (age != 0)
+ {
+ frameNdx = frameNdx - age;
+ DE_ASSERT(frameNdx >= 0);
+ frameOnBuffer.push_back(frameNdx);
+ age = bufferAges[frameNdx];
+ }
+
+ reverse(frameOnBuffer.begin(), frameOnBuffer.end());
+ return frameOnBuffer;
+}
+
+TestCase::IterateResult BufferAgeTest::iterate (void)
+{
+ de::Random rnd (m_seed);
+ const Library& egl = m_eglTestCtx.getLibrary();
+ tcu::TestLog& log = m_testCtx.getLog();
+ 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 = 20;
+ FrameSequence frameSequence;
+ vector<int> bufferAges;
+
+ if (m_preserveColorBuffer)
+ EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED));
+
+ for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
+ {
+ tcu::Surface currentBuffer (width, height);
+ tcu::Surface refBuffer (width, height);
+ Frame newFrame (width, height);
+ EGLint currentBufferAge = -1;
+
+ if (frameNdx % 2 == 0)
+ generateRandomFrame(&newFrame, m_evenFrameDrawType, rnd);
+ else
+ generateRandomFrame(&newFrame, m_oddFrameDrawType, rnd);
+
+ frameSequence.push_back(newFrame);
+
+ EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_EXT, ¤tBufferAge));
+
+ if (currentBufferAge > frameNdx || currentBufferAge < 0) // invalid buffer age
+ {
+ std::ostringstream stream;
+ stream << "Fail, the age is invalid. Age: " << currentBufferAge << ", frameNdx: " << frameNdx;
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
+ return STOP;
+ }
+
+ if (frameNdx > 0 && m_preserveColorBuffer && currentBufferAge != 1)
+ {
+ std::ostringstream stream;
+ stream << "Fail, EGL_BUFFER_PRESERVED is set to true, but buffer age is: " << currentBufferAge << " (should be 1)";
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
+ return STOP;
+ }
+
+ bufferAges.push_back(currentBufferAge);
+ DE_ASSERT((int)bufferAges.size() == frameNdx+1);
+
+ // during first half, just keep rendering without reading pixel back to mimic ordinary use case
+ if (frameNdx < numFrames/2)
+ {
+ if (currentBufferAge == 0)
+ clearColorScreen(m_gl, clearColor);
+
+ m_gles2Renderer->render(width, height, newFrame);
+ EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
+ continue;
+ }
+
+ // do verification in the second half
+ if (currentBufferAge > 0) //buffer contain previous content, need to verify
+ {
+ const vector<int> framesOnBuffer = getFramesOnBuffer(bufferAges, frameNdx);
+ readPixels(m_gl, ¤tBuffer);
+ clearColorReference(&refBuffer, clearColor);
+
+ for (vector<int>::const_iterator it = framesOnBuffer.begin(); it != framesOnBuffer.end(); it++)
+ m_refRenderer->render(&refBuffer, frameSequence[*it]);
+
+ if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx-currentBufferAge) == false)
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, buffer content is not well preserved when age > 0");
+ return STOP;
+ }
+ }
+ else // currentBufferAge == 0, content is undefined, clear the buffer, currentBufferAge < 0 is ruled out at the beginning
+ {
+ clearColorScreen(m_gl, clearColor);
+ clearColorReference(&refBuffer, clearColor);
+ }
+
+ m_gles2Renderer->render(width, height, newFrame);
+ m_refRenderer->render(&refBuffer, newFrame);
+
+ readPixels(m_gl, ¤tBuffer);
+
+ if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx) == false)
+ {
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, render result is wrong");
+ return STOP;
+ }
+
+ EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
+ }
+
+ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+ return STOP;
+}
+
+string generateDrawTypeName (const vector<BufferAgeTest::DrawType>& drawTypes)
+{
+ std::ostringstream stream;
+ if (drawTypes.size() == 0)
+ return string("_none");
+
+ for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
+ {
+ if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_RENDER)
+ stream << "_render";
+ else if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
+ stream << "_clear";
+ else
+ DE_ASSERT(false);
+ }
+ return stream.str();
+}
+
+string generateTestName (const vector<BufferAgeTest::DrawType>& oddFrameDrawType, const vector<BufferAgeTest::DrawType>& evenFrameDrawType)
+{
+ return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
+}
+
+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 preserveColorBuffer)
+{
+ eglu::FilterList filters;
+ filters << isWindow << isES2Renderable;
+ if (preserveColorBuffer)
+ 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);
+}
+
+void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
+{
+ tcu::clear(ref->getAccess(), clearColor);
+}
+
+void readPixels (const glw::Functions& gl, tcu::Surface* screen)
+{
+ gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
+}
+
+float windowToDeviceCoordinates (int x, int length)
+{
+ return (2.0f * float(x) / float(length)) - 1.0f;
+}
+
+bool compareToReference (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum)
+{
+ std::ostringstream stream;
+ stream << "FrameNdx = " << frameNdx << ", compare current buffer (numbered: " << bufferNum << ") to reference";
+ return tcu::intThresholdPositionDeviationCompare(log, "buffer age test", stream.str().c_str(), reference.getAccess(), buffer.getAccess(),
+ tcu::UVec4(8, 8, 8, 0), tcu::IVec3(2,2,0), true, tcu::COMPARE_LOG_RESULT);
+}
+
+} // anonymous
+
+BufferAgeTests::BufferAgeTests (EglTestContext& eglTestCtx)
+ : TestCaseGroup(eglTestCtx, "buffer_age", "Color buffer age tests")
+{
+}
+
+void BufferAgeTests::init (void)
+{
+ const BufferAgeTest::DrawType clearRender[2] =
+ {
+ BufferAgeTest::DRAWTYPE_GLES2_CLEAR,
+ BufferAgeTest::DRAWTYPE_GLES2_RENDER
+ };
+
+ const BufferAgeTest::DrawType renderClear[2] =
+ {
+ BufferAgeTest::DRAWTYPE_GLES2_RENDER,
+ BufferAgeTest::DRAWTYPE_GLES2_CLEAR
+ };
+
+ vector< vector<BufferAgeTest::DrawType> > frameDrawTypes;
+ frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> ());
+ frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
+ frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
+ frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
+ frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
+ frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
+ frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
+
+ for (int preserveNdx = 0; preserveNdx < 2; preserveNdx++)
+ {
+ const bool preserve = (preserveNdx == 0);
+ TestCaseGroup* const preserveGroup = new TestCaseGroup(m_eglTestCtx, (preserve ? "preserve" : "no_preserve"), "");
+
+ for (size_t evenNdx = 0; evenNdx < frameDrawTypes.size(); evenNdx++)
+ {
+ const vector<BufferAgeTest::DrawType>& evenFrameDrawType = frameDrawTypes[evenNdx];
+
+ for (size_t oddNdx = evenNdx; oddNdx < frameDrawTypes.size(); oddNdx++)
+ {
+ const vector<BufferAgeTest::DrawType>& oddFrameDrawType = frameDrawTypes[oddNdx];
+ const std::string name = generateTestName(oddFrameDrawType, evenFrameDrawType);
+ preserveGroup->addChild(new BufferAgeTest(m_eglTestCtx, preserve, oddFrameDrawType, evenFrameDrawType, name.c_str(), ""));
+ }
+ }
+ addChild(preserveGroup);
+ }
+}
+
+} // egl
+} // deqp
diff --git a/modules/egl/teglBufferAgeTests.hpp b/modules/egl/teglBufferAgeTests.hpp
new file mode 100644
index 0000000..fadf31a
--- /dev/null
+++ b/modules/egl/teglBufferAgeTests.hpp
@@ -0,0 +1,48 @@
+#ifndef _TEGLBUFFERAGETESTS_HPP
+#define _TEGLBUFFERAGETESTS_HPP
+/*-------------------------------------------------------------------------
+ * 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 EXT_buffer_age
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "teglTestCase.hpp"
+
+namespace deqp
+{
+namespace egl
+{
+
+class BufferAgeTests : public TestCaseGroup
+{
+public:
+ BufferAgeTests (EglTestContext& eglTestCtx);
+ void init (void);
+
+private:
+ BufferAgeTests (const BufferAgeTests&);
+ BufferAgeTests& operator= (const BufferAgeTests&);
+};
+
+} // egl
+} // deqp
+
+#endif // _TEGLBUFFERAGETESTS_HPP
diff --git a/modules/egl/teglTestPackage.cpp b/modules/egl/teglTestPackage.cpp
index 1336e14..a31eb60 100644
--- a/modules/egl/teglTestPackage.cpp
+++ b/modules/egl/teglTestPackage.cpp
@@ -56,6 +56,7 @@
#include "teglNativeColorMappingTests.hpp"
#include "teglNativeCoordMappingTests.hpp"
#include "teglResizeTests.hpp"
+#include "teglBufferAgeTests.hpp"
namespace deqp
{
@@ -124,6 +125,7 @@
addChild(new NativeCoordMappingTests (m_eglTestCtx));
addChild(new ReusableSyncTests (m_eglTestCtx));
addChild(new ResizeTests (m_eglTestCtx));
+ addChild(new BufferAgeTests (m_eglTestCtx));
}
};