/*------------------------------------------------------------------------- * drawElements Quality Program EGL Module * --------------------------------------- * * Copyright 2017 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 Robustness tests for KHR_robustness. *//*--------------------------------------------------------------------*/ #include "teglRobustnessTests.hpp" #include "tcuTestLog.hpp" #include "tcuStringTemplate.hpp" #include "egluConfigFilter.hpp" #include "egluStrUtil.hpp" #include "egluUtil.hpp" #include "eglwLibrary.hpp" #include "gluStrUtil.hpp" #include "gluShaderProgram.hpp" #include "gluDrawUtil.hpp" #include "glwFunctions.hpp" #include "glwEnums.hpp" #include "deSTLUtil.hpp" #include "deStringUtil.hpp" #include "deThread.hpp" #include "deSharedPtr.hpp" #include using std::string; using std::vector; using std::set; using tcu::TestLog; using namespace eglw; DE_STATIC_ASSERT(GL_RESET_NOTIFICATION_STRATEGY == 0x8256); DE_STATIC_ASSERT(GL_LOSE_CONTEXT_ON_RESET == 0x8252); DE_STATIC_ASSERT(GL_NO_RESET_NOTIFICATION == 0x8261); namespace deqp { namespace egl { namespace { enum ContextResetType { CONTEXTRESETTYPE_SHADER_OOB, CONTEXTRESETTYPE_FIXED_FUNC_OOB, }; enum ShaderType { SHADERTYPE_VERT, SHADERTYPE_FRAG, SHADERTYPE_COMPUTE, SHADERTYPE_VERT_AND_FRAG, }; enum ReadWriteType { READWRITETYPE_READ, READWRITETYPE_WRITE, }; enum ResourceType { RESOURCETYPE_UBO, RESOURCETYPE_SSBO, RESOURCETYPE_LOCAL_ARRAY, }; enum FixedFunctionType { FIXEDFUNCTIONTYPE_INDICES, FIXEDFUNCTIONTYPE_VERTICES, }; enum RobustAccessType { ROBUSTACCESS_TRUE, ROBUSTACCESS_FALSE, }; void requireEGLExtension (const Library& egl, EGLDisplay eglDisplay, const char* requiredExtension) { if (!eglu::hasExtension(egl, eglDisplay, requiredExtension)) TCU_THROW(NotSupportedError, (string(requiredExtension) + " not supported").c_str()); } bool isWindow (const eglu::CandidateConfig& c) { return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT; } template bool renderable (const eglu::CandidateConfig& c) { return (c.renderableType() & Type) == Type; } eglu::ConfigFilter getRenderableFilter (deUint32 bits) { switch (bits) { case EGL_OPENGL_ES2_BIT: return renderable; case EGL_OPENGL_ES3_BIT: return renderable; case EGL_OPENGL_BIT: return renderable; default: DE_FATAL("Unknown EGL bitfied value"); return renderable<0>; } } const char* eglResetNotificationStrategyToString (EGLint strategy) { switch (strategy) { case EGL_NO_RESET_NOTIFICATION_KHR: return "EGL_NO_RESET_NOTIFICATION_KHR"; case EGL_LOSE_CONTEXT_ON_RESET_KHR: return "EGL_LOSE_CONTEXT_ON_RESET_KHR"; default: return ""; } } void logAttribList (const EglTestContext& eglTestCtx, const EGLint* attribList) { const EGLint* iter = &(attribList[0]); std::ostringstream attribListString; while ((*iter) != EGL_NONE) { switch (*iter) { // case EGL_CONTEXT_CLIENT_VERSION: case EGL_CONTEXT_MAJOR_VERSION_KHR: iter++; attribListString << "EGL_CONTEXT_CLIENT_VERSION, " << (*iter) << ", "; iter++; break; case EGL_CONTEXT_MINOR_VERSION_KHR: iter++; attribListString << "EGL_CONTEXT_MINOR_VERSION_KHR, " << (*iter) << ", "; iter++; break; case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: iter++; attribListString << "EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, " << eglResetNotificationStrategyToString(*iter) << ", "; iter++; break; case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR: iter++; attribListString << "EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, " << eglResetNotificationStrategyToString(*iter) << ", "; iter++; break; case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: iter++; attribListString << "EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, "; if (*iter == EGL_FALSE || *iter == EGL_TRUE) attribListString << (*iter ? "EGL_TRUE" : "EGL_FALSE") << ", "; else attribListString << (*iter) << ", "; iter++; break; default: DE_FATAL("Unsupported attribute"); } } attribListString << "EGL_NONE"; eglTestCtx.getTestContext().getLog() << TestLog::Message << "EGL attrib list: { " << attribListString.str() << " }\n\n" << TestLog::EndMessage; } class RobustnessTestCase: public TestCase { public: class Params { public: Params (void) {} Params (const string& name, const string& description, const RobustAccessType& robustAccessType, const ContextResetType& contextResetType, const FixedFunctionType& fixedFunctionType); Params (const string& name, const string& description, const RobustAccessType& robustAccessType, const ContextResetType& contextResetType, const ShaderType& shaderType, const ResourceType& resourceType, const ReadWriteType& readWriteType); const string& getName (void) const { return m_name; } const string& getDescription (void) const { return m_description; } const ContextResetType& getContextResetType (void) const { return m_contextResetType; } const ShaderType& getShaderType (void) const { return m_shaderType; } const ResourceType& getResourceType (void) const { return m_resourceType; } const ReadWriteType& getReadWriteType (void) const { return m_readWriteType; } const FixedFunctionType& getFixedFunctionType (void) const { return m_fixedFunctionType; } const RobustAccessType& getRobustAccessType (void) const { return m_robustAccessType; } private: string m_name; string m_description; RobustAccessType m_robustAccessType; ContextResetType m_contextResetType; ShaderType m_shaderType; ResourceType m_resourceType; ReadWriteType m_readWriteType; FixedFunctionType m_fixedFunctionType; }; RobustnessTestCase (EglTestContext& eglTestCtx, const char* name, const char* description); RobustnessTestCase (EglTestContext& eglTestCtx, const char* name, const char* description, Params params); ~RobustnessTestCase (void); void checkRequiredEGLExtensions (const EGLint* attribList); protected: Params m_params; EGLDisplay m_eglDisplay; EGLConfig m_eglConfig; EGLSurface m_eglSurface; private: void init (void); void deinit (void); void initEGLSurface (void); EGLConfig getEGLConfig (void); eglu::NativeWindow* m_window; }; RobustnessTestCase::Params::Params (const string& name, const string& description, const RobustAccessType& robustAccessType, const ContextResetType& contextResetType, const FixedFunctionType& fixedFunctionType) : m_name (name) , m_description (description) , m_robustAccessType (robustAccessType) , m_contextResetType (contextResetType) , m_fixedFunctionType (fixedFunctionType) { } RobustnessTestCase::Params::Params (const string& name, const string& description, const RobustAccessType& robustAccessType, const ContextResetType& contextResetType, const ShaderType& shaderType, const ResourceType& resourceType, const ReadWriteType& readWriteType) : m_name (name) , m_description (description) , m_robustAccessType (robustAccessType) , m_contextResetType (contextResetType) , m_shaderType (shaderType) , m_resourceType (resourceType) , m_readWriteType (readWriteType) { } RobustnessTestCase::RobustnessTestCase (EglTestContext& eglTestCtx, const char* name, const char* description) : TestCase (eglTestCtx, name, description) , m_eglDisplay (EGL_NO_DISPLAY) , m_eglConfig (0) , m_eglSurface (EGL_NO_SURFACE) , m_window (DE_NULL) { } RobustnessTestCase::RobustnessTestCase (EglTestContext& eglTestCtx, const char* name, const char* description, Params params) : TestCase (eglTestCtx, name, description) , m_params (params) , m_eglDisplay (EGL_NO_DISPLAY) , m_eglConfig (0) , m_eglSurface (EGL_NO_SURFACE) , m_window (DE_NULL) { } RobustnessTestCase::~RobustnessTestCase (void) { deinit(); } void RobustnessTestCase::init (void) { m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()); m_eglConfig = getEGLConfig(); initEGLSurface(); } void RobustnessTestCase::deinit (void) { const Library& egl = m_eglTestCtx.getLibrary(); 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; } EGLConfig RobustnessTestCase::getEGLConfig (void) { eglu::FilterList filters; filters << isWindow << getRenderableFilter(EGL_OPENGL_ES3_BIT); return eglu::chooseSingleConfig(m_eglTestCtx.getLibrary(), m_eglDisplay, filters); } void RobustnessTestCase::initEGLSurface (void) { EGLU_CHECK_CALL(m_eglTestCtx.getLibrary(), bindAPI(EGL_OPENGL_ES_API)); const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine()); const eglu::WindowParams windowParams = eglu::WindowParams(256, 256, eglu::parseWindowVisibility(m_testCtx.getCommandLine())); m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, m_eglConfig, DE_NULL, windowParams); m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, m_eglConfig, DE_NULL); } glu::ApiType paramsToApiType (const RobustnessTestCase::Params& params) { EGLint minorVersion = 0; if (params.getShaderType() == SHADERTYPE_COMPUTE || params.getResourceType() == RESOURCETYPE_SSBO || params.getContextResetType() == CONTEXTRESETTYPE_SHADER_OOB) { minorVersion = 1; } return glu::ApiType::es(3, minorVersion); } void RobustnessTestCase::checkRequiredEGLExtensions (const EGLint* attribList) { set requiredExtensions; vector extensions = eglu::getDisplayExtensions(m_eglTestCtx.getLibrary(), m_eglDisplay); { const EGLint* iter = attribList; while ((*iter) != EGL_NONE) { switch (*iter) { case EGL_CONTEXT_MAJOR_VERSION_KHR: iter++; iter++; break; case EGL_CONTEXT_MINOR_VERSION_KHR: iter++; requiredExtensions.insert("EGL_KHR_create_context"); iter++; break; case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: iter++; requiredExtensions.insert("EGL_EXT_create_context_robustness"); iter++; break; default: DE_ASSERT(DE_FALSE); } } } for (std::set::const_iterator reqExt = requiredExtensions.begin(); reqExt != requiredExtensions.end(); ++reqExt) { if (!de::contains(extensions.begin(), extensions.end(), *reqExt)) { const char* const extension = reqExt->c_str(); requireEGLExtension(m_eglTestCtx.getLibrary(), m_eglDisplay, extension); } } } void checkRequiredGLSupport (const glw::Functions& gl, glu::ApiType requiredApi) { if (!glu::hasExtension(gl, requiredApi, "GL_KHR_robustness") && !glu::hasExtension(gl, requiredApi, "GL_EXT_robustness")) { TCU_THROW(NotSupportedError, (string("GL_KHR_robustness and GL_EXT_robustness") + " not supported").c_str()); } else { int realMinorVersion = 0; gl.getIntegerv(GL_MINOR_VERSION, &realMinorVersion); GLU_EXPECT_NO_ERROR(gl.getError(), "Get minor version failed"); if (realMinorVersion < requiredApi.getMinorVersion()) TCU_THROW(NotSupportedError, "Test case requires GLES 3.1"); } } void checkGLSupportForParams (const glw::Functions& gl, const RobustnessTestCase::Params& params) { int minorVersion = 0; if (params.getShaderType() == SHADERTYPE_COMPUTE || params.getResourceType() == RESOURCETYPE_SSBO || params.getContextResetType() == CONTEXTRESETTYPE_SHADER_OOB) { minorVersion = 1; } checkRequiredGLSupport(gl, glu::ApiType::es(3, minorVersion)); } class RenderingContext { public: RenderingContext (const EglTestContext& eglTestCtx, const EGLint* attribList, const EGLConfig& config, const EGLDisplay& display, const EGLContext& sharedContext); ~RenderingContext (void); void initGLFunctions (glw::Functions* gl, const glu::ApiType apiType); void makeCurrent (const EGLSurface& surface); EGLContext getContext (void); private: const EglTestContext& m_eglTestCtx; const EGLint* m_attribList; const EGLConfig& m_config; const EGLDisplay& m_display; const Library& m_egl; EGLContext m_context; void createContext (const EGLConfig& sharedConfig); void destroyContext (void); RenderingContext (const RenderingContext&); RenderingContext& operator= (const RenderingContext&); }; RenderingContext::RenderingContext (const EglTestContext& eglTestCtx, const EGLint* attribList, const EGLConfig& config, const EGLDisplay& display, const EGLContext& sharedContext) : m_eglTestCtx (eglTestCtx) , m_attribList (attribList) , m_config (config) , m_display (display) , m_egl (eglTestCtx.getLibrary()) , m_context (EGL_NO_CONTEXT) { logAttribList(eglTestCtx, m_attribList); createContext(sharedContext); } RenderingContext::~RenderingContext (void) { destroyContext(); } void RenderingContext::createContext (const EGLConfig& sharedContext) { m_context = m_egl.createContext(m_display, m_config, sharedContext, m_attribList); EGLU_CHECK_MSG(m_egl, "eglCreateContext()"); } void RenderingContext::destroyContext (void) { EGLU_CHECK_CALL(m_eglTestCtx.getLibrary(), makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); if (m_context != EGL_NO_CONTEXT) m_egl.destroyContext(m_display, m_context); } void RenderingContext::makeCurrent (const EGLSurface& surface) { EGLU_CHECK_CALL(m_egl, makeCurrent(m_display, surface, surface, m_context)); } void RenderingContext::initGLFunctions (glw::Functions *gl, const glu::ApiType apiType) { // \todo [2017-03-23 pyry] Current version has 2 somewhat ugly hacks: // // 1) Core functions are loaded twice. We need glGetString(i) to query supported // extensions to determine if we need to load EXT or KHR-suffixed robustness // functions. This could be fixed by exposing glw::FunctionLoader in EglTestContext // for example. // // 2) We assume that calling code will check for KHR_robustness or EXT_robustness // support after calling initGLFunctions(). We could move the check here. m_eglTestCtx.initGLFunctions(gl, apiType); { const char* const robustnessExt = glu::hasExtension(*gl, apiType, "GL_KHR_robustness") ? "GL_KHR_robustness" : "GL_EXT_robustness"; const char* const extensions[] = { robustnessExt }; m_eglTestCtx.initGLFunctions(gl, apiType, DE_LENGTH_OF_ARRAY(extensions), &extensions[0]); } } EGLContext RenderingContext::getContext (void) { return m_context; } class ContextReset { public: ContextReset (glw::Functions& gl, tcu::TestLog& log, FixedFunctionType fixedFunctionType); ContextReset (glw::Functions& gl, tcu::TestLog& log, ShaderType shaderType, ResourceType resourceType, ReadWriteType readWriteType); virtual ~ContextReset (void) {} virtual void setup (void) = 0; virtual void draw (void) = 0; virtual void teardown (void) = 0; void finish (void); glw::GLint getError (void); glw::GLint getGraphicsResetStatus (void); glw::GLsync getSyncObject (void) const { return m_sync; } glw::GLuint getQueryID (void) const { return m_queryID; } glw::Functions& m_gl; tcu::TestLog& m_log; ShaderType m_shaderType; ResourceType m_resourceType; ReadWriteType m_readWriteType; FixedFunctionType m_fixedFunctionType; private: ContextReset (const ContextReset&); ContextReset& operator= (const ContextReset&); glw::GLuint m_queryID; glw::GLsync m_sync; }; ContextReset::ContextReset (glw::Functions& gl, tcu::TestLog& log, FixedFunctionType fixedFunctionType) : m_gl (gl) , m_log (log) , m_fixedFunctionType (fixedFunctionType) { } ContextReset::ContextReset (glw::Functions& gl, tcu::TestLog& log, ShaderType shaderType, ResourceType resourceType, ReadWriteType readWriteType) : m_gl (gl) , m_log (log) , m_shaderType (shaderType) , m_resourceType (resourceType) , m_readWriteType (readWriteType) { } void ContextReset::finish (void) { GLU_CHECK_GLW_CALL(m_gl, finish()); } glw::GLint ContextReset::getError (void) { glw::GLint error; error = m_gl.getError(); return error; } glw::GLint ContextReset::getGraphicsResetStatus (void) { glw::GLint resetStatus; resetStatus = m_gl.getGraphicsResetStatus(); return resetStatus; } class FixedFunctionOOB : public ContextReset { public: FixedFunctionOOB (glw::Functions& gl, tcu::TestLog& log, FixedFunctionType fixedFunctionType); ~FixedFunctionOOB (void); struct TestConfig { int textureWidth; int textureHeight; }; virtual void setup (void); virtual void draw (void); virtual void teardown (void); private: glu::ProgramSources genSources (void); glw::GLuint m_coordinatesBuffer; glw::GLint m_coordLocation; }; FixedFunctionOOB::FixedFunctionOOB (glw::Functions& gl, tcu::TestLog& log, FixedFunctionType fixedFunctionType) : ContextReset(gl, log, fixedFunctionType) , m_coordinatesBuffer (0) , m_coordLocation (0) { } FixedFunctionOOB::~FixedFunctionOOB (void) { try { // Reset GL_CONTEXT_LOST error before destroying resources m_gl.getGraphicsResetStatus(); teardown(); } catch (...) { // Ignore GL errors from teardown() } } glu::ProgramSources FixedFunctionOOB::genSources (void) { const char* const vert = "#version 300 es\n" "in highp vec4 a_position;\n" "void main (void)\n" "{\n" " gl_Position = a_position;\n" "}\n"; const char* const frag = "#version 300 es\n" "layout(location = 0) out highp vec4 fragColor;\n" "void main (void)\n" "{\n" " fragColor = vec4(1.0f);\n" "}\n"; return glu::ProgramSources() << glu::VertexSource(vert) << glu::FragmentSource(frag); } void FixedFunctionOOB::setup (void) { glu::ShaderProgram program(m_gl, genSources()); m_log << program; if (!program.isOk()) TCU_FAIL("Failed to compile shader program"); GLU_CHECK_GLW_CALL(m_gl, useProgram(program.getProgram())); const glw::GLfloat coords[] = { -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f }; m_coordLocation = m_gl.getAttribLocation(program.getProgram(), "a_position"); GLU_CHECK_GLW_MSG(m_gl, "glGetAttribLocation()"); TCU_CHECK(m_coordLocation != (glw::GLint)-1); // Load the vertex data m_coordinatesBuffer = 0; GLU_CHECK_GLW_CALL(m_gl, genBuffers(1, &m_coordinatesBuffer)); GLU_CHECK_GLW_CALL(m_gl, bindBuffer(GL_ARRAY_BUFFER, m_coordinatesBuffer)); GLU_CHECK_GLW_CALL(m_gl, bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)sizeof(coords), coords, GL_STATIC_DRAW)); GLU_CHECK_GLW_CALL(m_gl, enableVertexAttribArray(m_coordLocation)); GLU_CHECK_GLW_CALL(m_gl, vertexAttribPointer(m_coordLocation, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL)); } void FixedFunctionOOB::draw (void) { const glw::GLint bad_indices[] = {0, 10, 100, 1000, 10000, 100000}; if (m_fixedFunctionType == FIXEDFUNCTIONTYPE_INDICES) m_gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, bad_indices); else if (m_fixedFunctionType == FIXEDFUNCTIONTYPE_VERTICES) m_gl.drawArrays(GL_TRIANGLES, 0, 1000); else DE_FATAL("Unknown fixed function type"); } void FixedFunctionOOB::teardown (void) { if (m_coordLocation) { GLU_CHECK_GLW_CALL(m_gl, disableVertexAttribArray(m_coordLocation)); m_coordLocation = 0; } if (m_coordinatesBuffer) { GLU_CHECK_GLW_CALL(m_gl, deleteBuffers(1, &m_coordinatesBuffer)); m_coordinatesBuffer = 0; } GLU_CHECK_GLW_CALL(m_gl, useProgram(0)); } class ShadersOOB : public ContextReset { public: ShadersOOB (glw::Functions& gl, tcu::TestLog& log, ShaderType shaderType, ResourceType resourceType, ReadWriteType readWriteType); ~ShadersOOB (void); virtual void setup (void); virtual void draw (void); virtual void teardown (void); private: static const int s_numBindings = 3; glw::GLuint m_coordinatesBuffer; glw::GLint m_coordLocation; bool m_isUBO; bool m_isRead; bool m_isLocalArray; std::vector m_buffers; std::string genVertexShader (const std::string& shaderDecl, const std::string& shaderBody); std::string genFragmentShader (const std::string& shaderDecl, const std::string& shaderBody); std::string genComputeShader (const std::string& shaderDecl, const std::string& shaderBody); glu::ProgramSources genNonComputeSource (void); glu::ProgramSources genComputeSource (void); glu::ProgramSources genSources (void); }; ShadersOOB::ShadersOOB (glw::Functions& gl, tcu::TestLog& log, ShaderType shaderType, ResourceType resourceType, ReadWriteType readWriteType) : ContextReset(gl, log, shaderType, resourceType, readWriteType) , m_coordinatesBuffer (0) , m_coordLocation (0) , m_buffers (s_numBindings, 0) { m_isUBO = (m_resourceType == RESOURCETYPE_UBO); m_isLocalArray = (m_resourceType == RESOURCETYPE_LOCAL_ARRAY); m_isRead = (m_readWriteType == READWRITETYPE_READ); } ShadersOOB::~ShadersOOB (void) { try { // Reset GL_CONTEXT_LOST error before destroying resources m_gl.getGraphicsResetStatus(); teardown(); } catch (...) { // Ignore GL errors from teardown() } } std::string ShadersOOB::genVertexShader (const std::string& shaderDecl, const std::string& shaderBody) { static const char* const s_simpleVertexShaderSource = "#version 310 es\n" "in highp vec4 a_position;\n" "void main (void)\n" "{\n" " gl_Position = a_position;\n" "}\n"; switch (m_shaderType) { case SHADERTYPE_VERT: case SHADERTYPE_VERT_AND_FRAG: { std::ostringstream vertexShaderSource; vertexShaderSource << "#version 310 es\n" << "in highp vec4 a_position;\n" << "out highp vec4 v_color;\n" << shaderDecl << "\n" << "void main (void)\n" << "{\n" << " highp vec4 color = vec4(0.0f);\n" << shaderBody << "\n" << " v_color = color;\n" << " gl_Position = a_position;\n" << "}\n"; return vertexShaderSource.str(); } case SHADERTYPE_FRAG: return s_simpleVertexShaderSource; default: DE_FATAL("Unknown shader type"); return ""; } } std::string ShadersOOB::genFragmentShader (const std::string& shaderDecl, const std::string& shaderBody) { static const char* const s_simpleFragmentShaderSource = "#version 310 es\n" "in highp vec4 v_color;\n" "layout(location = 0) out highp vec4 fragColor;\n" "void main (void)\n" "{\n" " fragColor = v_color;\n" "}\n"; switch (m_shaderType) { case SHADERTYPE_VERT: return s_simpleFragmentShaderSource; case SHADERTYPE_FRAG: { std::ostringstream fragmentShaderSource; fragmentShaderSource << "#version 310 es\n" << "layout(location = 0) out highp vec4 fragColor;\n" << shaderDecl << "\n" << "void main (void)\n" << "{\n" << " highp vec4 color = vec4(0.0f);\n" << shaderBody << "\n" << " fragColor = color;\n" << "}\n"; return fragmentShaderSource.str(); } case SHADERTYPE_VERT_AND_FRAG: { std::ostringstream fragmentShaderSource; fragmentShaderSource << "#version 310 es\n" << "in highp vec4 v_color;\n" << "layout(location = 0) out highp vec4 fragColor;\n" << shaderDecl << "\n" << "void main (void)\n" << "{\n" << " highp vec4 color = vec4(0.0f);\n" << shaderBody << "\n" << " fragColor = color;\n" << "}\n"; return fragmentShaderSource.str(); } default: DE_FATAL("Unknown shader type"); return ""; } } std::string ShadersOOB::genComputeShader (const std::string& shaderDecl, const std::string& shaderBody) { std::ostringstream computeShaderSource; computeShaderSource << "#version 310 es\n" << "layout(local_size_x = 1, local_size_y = 1) in;\n" << "\n" << "layout(binding = 0) buffer Output {\n" << " highp vec4 values;\n" << "} sb_out;\n" << "\n" << shaderDecl << "void main ()\n" << "{\n" << shaderBody << "}\n"; return computeShaderSource.str(); } glu::ProgramSources ShadersOOB::genNonComputeSource (void) { std::ostringstream shaderDecl; std::ostringstream shaderBody; shaderDecl << "uniform highp int u_index;\n"; if (m_isLocalArray) { const char* const readWriteStatement = (m_isRead) ? " color.x = color_out[u_index];\n" : " color[u_index] = color_out[0];\n"; shaderBody << " highp float color_out[4] = float[4](0.25f, 0.5f, 0.75f, 1.0f);\n" << readWriteStatement; } else { const std::string resName = (m_isUBO) ? "ub_in" : "sb_in"; shaderDecl << "layout(std140, binding = 0) " << ((m_isUBO) ? "uniform" : "buffer") << " Block\n" << "{\n" << " highp float color_out[4];\n" << "} " << resName << "[" << s_numBindings << "];\n"; const std::string readWriteStatement = (m_isRead) ? " color.x = " + resName + "[0].color_out[u_index];\n" : " color[u_index] = " + resName + "[0].color_out[0];\n"; shaderBody << readWriteStatement; } return glu::ProgramSources() << glu::VertexSource(genVertexShader(shaderDecl.str(), shaderBody.str())) << glu::FragmentSource(genFragmentShader(shaderDecl.str(), shaderBody.str())); } glu::ProgramSources ShadersOOB::genComputeSource (void) { std::ostringstream shaderDecl; std::ostringstream shaderBody; shaderDecl << "uniform highp int u_index;\n"; shaderBody << " uvec3 size = gl_NumWorkGroups * gl_WorkGroupSize;\n" << " uint groupNdx = size.x*gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;\n"; if (m_isLocalArray) { const char* const readWriteStatement = (m_isRead) ? " sb_out.values.x = values[u_index];\n" : " sb_out.values[u_index] = values.x;\n"; shaderBody << " highp vec4 values = vec4(1.0f, 0.0f, 3.0f, 2.0f) * float(groupNdx);\n" << readWriteStatement; } else { const std::string resName = (m_isUBO) ? "ub_in" : "sb_in"; shaderDecl << "layout(std140, binding = 1) " << ((m_isUBO) ? "uniform" : "buffer") << " Input\n" << "{\n" << " highp vec4 values;\n" << "} " << resName << "[" << s_numBindings << "];\n"; std::string readWriteStatement = (m_isRead) ? " sb_out.values.x = " + resName + "[0].values[u_index] * float(groupNdx);\n" : " sb_out.values[u_index] = " + resName + "[0].values.x * float(groupNdx);\n"; shaderBody << readWriteStatement; } return glu::ProgramSources() << glu::ComputeSource(genComputeShader(shaderDecl.str(), shaderBody.str())); } glu::ProgramSources ShadersOOB::genSources (void) { if (m_shaderType == SHADERTYPE_COMPUTE) return genComputeSource(); else return genNonComputeSource(); } void ShadersOOB::setup (void) { if (!m_isUBO && !m_isLocalArray && (m_shaderType != SHADERTYPE_COMPUTE)) { // Check implementation limits for shader SSBO int shaderStorageBlockSupported = -1; const bool isVertex = (m_shaderType == SHADERTYPE_VERT || m_shaderType == SHADERTYPE_VERT_AND_FRAG) ? true : false; string shaderTypeStr = isVertex ? "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS" : "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS"; GLU_CHECK_GLW_CALL(m_gl, getIntegerv(isVertex ? GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS : GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &shaderStorageBlockSupported)); if (shaderStorageBlockSupported < (int)m_buffers.size()) TCU_THROW(NotSupportedError, ("Test requires " + shaderTypeStr + " >= " + de::toString((int)m_buffers.size()) + ", got " + de::toString(shaderStorageBlockSupported)).c_str()); } glu::ShaderProgram program(m_gl, genSources()); m_log << program; if (!program.isOk()) TCU_FAIL("Failed to compile shader program"); GLU_CHECK_GLW_CALL(m_gl, useProgram(program.getProgram())); const glw::GLint indexLocation = m_gl.getUniformLocation(program.getProgram(), "u_index"); GLU_CHECK_GLW_MSG(m_gl, "glGetUniformLocation()"); TCU_CHECK(indexLocation != (glw::GLint)-1); const glw::GLint index = -1; GLU_CHECK_GLW_CALL(m_gl, uniform1i(indexLocation, index)); if (m_shaderType != SHADERTYPE_COMPUTE) { const glw::GLfloat coords[] = { -1.0f, -1.0f, +1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f }; // Setup vertices position m_coordLocation = m_gl.getAttribLocation(program.getProgram(), "a_position"); GLU_CHECK_GLW_MSG(m_gl, "glGetAttribLocation()"); TCU_CHECK(m_coordLocation != (glw::GLint)-1); // Load the vertex data m_coordinatesBuffer = 0; GLU_CHECK_GLW_CALL(m_gl, genBuffers(1, &m_coordinatesBuffer)); GLU_CHECK_GLW_CALL(m_gl, bindBuffer(GL_ARRAY_BUFFER, m_coordinatesBuffer)); GLU_CHECK_GLW_CALL(m_gl, bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)sizeof(coords), coords, GL_STATIC_DRAW)); GLU_CHECK_GLW_CALL(m_gl, enableVertexAttribArray(m_coordLocation)); GLU_CHECK_GLW_CALL(m_gl, vertexAttribPointer(m_coordLocation, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL)); } // Create unused data for filling buffer objects const std::vector refValues(s_numBindings, tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f)); if (m_isLocalArray && m_shaderType == SHADERTYPE_COMPUTE) { // Setup output buffer GLU_CHECK_GLW_CALL(m_gl, genBuffers((glw::GLsizei)1u, &m_buffers[0])); GLU_CHECK_GLW_CALL(m_gl, bindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffers[0])); GLU_CHECK_GLW_CALL(m_gl, bufferData(GL_SHADER_STORAGE_BUFFER, sizeof(tcu::Vec4), &(refValues[0]), GL_STATIC_DRAW)); GLU_CHECK_GLW_CALL(m_gl, bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffers[0])); } else if (!m_isLocalArray) { // Set up interface block of buffer bindings GLU_CHECK_GLW_CALL(m_gl, genBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0])); for (int bufNdx = 0; bufNdx < (int)m_buffers.size(); ++bufNdx) { const glw::GLenum resType = m_isUBO && (m_shaderType != SHADERTYPE_COMPUTE || bufNdx != 0) ? GL_UNIFORM_BUFFER : GL_SHADER_STORAGE_BUFFER; GLU_CHECK_GLW_CALL(m_gl, bindBuffer(resType, m_buffers[bufNdx])); GLU_CHECK_GLW_CALL(m_gl, bufferData(resType, sizeof(tcu::Vec4), &(refValues[bufNdx]), GL_STATIC_DRAW)); GLU_CHECK_GLW_CALL(m_gl, bindBufferBase(resType, bufNdx, m_buffers[bufNdx])); } } } void ShadersOOB::draw (void) { if (m_shaderType == SHADERTYPE_COMPUTE) m_gl.dispatchCompute(1, 1, 1); else { const glw::GLuint indices[] = {0, 1, 2, 2, 3, 0}; m_gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, indices); } } void ShadersOOB::teardown (void) { if (m_shaderType != SHADERTYPE_COMPUTE) { if (m_coordLocation) { GLU_CHECK_GLW_CALL(m_gl, disableVertexAttribArray(m_coordLocation)); m_coordLocation = 0; } } if (m_coordinatesBuffer) { GLU_CHECK_GLW_CALL(m_gl, deleteBuffers(1, &m_coordinatesBuffer)); m_coordinatesBuffer = 0; } if (!m_isLocalArray) { if (!m_buffers.empty()) { GLU_CHECK_GLW_CALL(m_gl, deleteBuffers((glw::GLsizei)m_buffers.size(), &m_buffers[0])); m_buffers.clear(); } } GLU_CHECK_GLW_CALL(m_gl, useProgram(0)); } class QueryRobustAccessCase : public RobustnessTestCase { public: QueryRobustAccessCase (EglTestContext& eglTestCtx, const char* name, const char* description) : RobustnessTestCase (eglTestCtx, name, description) {} TestCase::IterateResult iterate (void) { TestLog& log = m_testCtx.getLog(); log << tcu::TestLog::Message << "Check that after successfully creating a robust context the robust access query returned by glBooleanv() equals GL_TRUE\n\n" << tcu::TestLog::EndMessage; const EGLint attribList[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 0, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_TRUE, EGL_NONE }; checkRequiredEGLExtensions(attribList); RenderingContext context(m_eglTestCtx, attribList, m_eglConfig, m_eglDisplay, EGL_NO_CONTEXT); context.makeCurrent(m_eglSurface); glw::Functions gl; { const glu::ApiType apiType(3, 0, glu::PROFILE_ES); context.initGLFunctions(&gl, apiType); checkRequiredGLSupport(gl, apiType); } deUint8 robustAccessGL; gl.getBooleanv(GL_CONTEXT_ROBUST_ACCESS_EXT, &robustAccessGL); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBooleanv()"); if (robustAccessGL != GL_TRUE) { log << TestLog::Message << "Invalid GL_CONTEXT_ROBUST_ACCESS returned by glGetBooleanv(). Got '" << robustAccessGL << "' expected GL_TRUE." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); return STOP; } m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; } }; class NoResetNotificationCase : public RobustnessTestCase { public: NoResetNotificationCase (EglTestContext& eglTestCtx, const char* name, const char* description) : RobustnessTestCase (eglTestCtx, name, description) {} TestCase::IterateResult iterate (void) { TestLog& log = m_testCtx.getLog(); log << tcu::TestLog::Message << "Check the reset notification strategy returned by glGetIntegerv() equals GL_NO_RESET_NOTIFICATION\n\n" << tcu::TestLog::EndMessage; const EGLint attribList[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 0, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_TRUE, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_NO_RESET_NOTIFICATION, EGL_NONE }; checkRequiredEGLExtensions(attribList); RenderingContext context(m_eglTestCtx, attribList, m_eglConfig, m_eglDisplay, EGL_NO_CONTEXT); context.makeCurrent(m_eglSurface); glw::Functions gl; { const glu::ApiType apiType(3, 0, glu::PROFILE_ES); context.initGLFunctions(&gl, apiType); checkRequiredGLSupport(gl, apiType); } deUint8 robustAccessGL; gl.getBooleanv(GL_CONTEXT_ROBUST_ACCESS_EXT, &robustAccessGL); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBooleanv()"); glw::GLint reset = 0; gl.getIntegerv(GL_RESET_NOTIFICATION_STRATEGY, &reset); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv()"); if (reset != GL_NO_RESET_NOTIFICATION) { log << tcu::TestLog::Message << "Test failed! glGetIntegerv() returned wrong value. [" << glu::getErrorStr(reset) << ", expected " << glu::getErrorStr(GL_NO_RESET_NOTIFICATION) << "]" << tcu::TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); return STOP; } GLU_CHECK_GLW_CALL(gl, getGraphicsResetStatus()); m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; } }; class LoseContextOnResetCase : public RobustnessTestCase { public: LoseContextOnResetCase (EglTestContext& eglTestCtx, const char* name, const char* description) : RobustnessTestCase(eglTestCtx, name, description) {} TestCase::IterateResult iterate (void) { TestLog& log = m_testCtx.getLog(); log << tcu::TestLog::Message << "Check the reset notification strategy returned by glGetIntegerv() equals GL_LOSE_CONTEXT_ON_RESET\n\n" << tcu::TestLog::EndMessage; const EGLint attribList[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 0, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_TRUE, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_LOSE_CONTEXT_ON_RESET, EGL_NONE }; checkRequiredEGLExtensions(attribList); RenderingContext context(m_eglTestCtx, attribList, m_eglConfig, m_eglDisplay, EGL_NO_CONTEXT); context.makeCurrent(m_eglSurface); glw::Functions gl; { const glu::ApiType apiType(3, 0, glu::PROFILE_ES); context.initGLFunctions(&gl, apiType); checkRequiredGLSupport(gl, apiType); } glw::GLint reset = 0; gl.getIntegerv(GL_RESET_NOTIFICATION_STRATEGY, &reset); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv()"); if (reset != GL_LOSE_CONTEXT_ON_RESET) { log << tcu::TestLog::Message << "Test failed! glGetIntegerv() returned wrong value. [" << reset << ", expected " << glu::getErrorStr(GL_LOSE_CONTEXT_ON_RESET) << "]" << tcu::TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); return STOP; } log << tcu::TestLog::Message << "Check the graphics reset status returned by glGetGraphicsResetStatus() " << "equals GL_NO_ERROR\n" << tcu::TestLog::EndMessage; GLU_CHECK_GLW_CALL(gl, getGraphicsResetStatus()); m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; } }; de::SharedPtr contextResetFactory (const RobustnessTestCase::Params params, glw::Functions& gl, tcu::TestLog& log) { if (params.getContextResetType() == CONTEXTRESETTYPE_FIXED_FUNC_OOB) return de::SharedPtr(new FixedFunctionOOB(gl, log, params.getFixedFunctionType())); if (params.getContextResetType() == CONTEXTRESETTYPE_SHADER_OOB) return de::SharedPtr(new ShadersOOB(gl, log, params.getShaderType(), params.getResourceType(), params.getReadWriteType())); else { DE_FATAL("Unknown context reset type"); return de::SharedPtr(DE_NULL); } } class ContextResetCase : public RobustnessTestCase { public: ContextResetCase (EglTestContext& eglTestCtx, const char* name, const char* description, Params params); virtual ~ContextResetCase (void) {} virtual void provokeReset (de::SharedPtr& contextReset) = 0; virtual void waitForReset (de::SharedPtr& contextReset) = 0; virtual void passAndLog (de::SharedPtr& contextReset) = 0; TestCase::IterateResult iterate (void); void execute (glw::Functions& gl); private: ContextResetCase (const ContextResetCase&); ContextResetCase& operator= (const ContextResetCase&); }; ContextResetCase::ContextResetCase (EglTestContext& eglTestCtx, const char* name, const char* description, Params params) : RobustnessTestCase (eglTestCtx, name, description, params) {} TestCase::IterateResult ContextResetCase::iterate (void) { glw::Functions gl; const EGLint attribList[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 0, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, (m_params.getRobustAccessType() == ROBUSTACCESS_TRUE) ? EGL_TRUE : EGL_FALSE, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_LOSE_CONTEXT_ON_RESET, EGL_NONE }; checkRequiredEGLExtensions(attribList); RenderingContext context(m_eglTestCtx, attribList, m_eglConfig, m_eglDisplay, EGL_NO_CONTEXT); context.makeCurrent(m_eglSurface); { const glu::ApiType apiType = paramsToApiType(m_params); context.initGLFunctions(&gl, apiType); checkGLSupportForParams(gl, m_params); } execute(gl); return STOP; } void ContextResetCase::execute (glw::Functions& gl) { de::SharedPtr contextReset = contextResetFactory(m_params, gl, m_testCtx.getLog()); glw::GLboolean isContextRobust = GL_FALSE; GLU_CHECK_GLW_CALL(gl, getBooleanv(GL_CONTEXT_ROBUST_ACCESS_EXT, &isContextRobust)); provokeReset(contextReset); if (m_params.getContextResetType() == CONTEXTRESETTYPE_SHADER_OOB || m_params.getContextResetType() == CONTEXTRESETTYPE_FIXED_FUNC_OOB) { try { waitForReset(contextReset); m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Context was NOT lost. Test skipped"); } catch (const glu::Error& error) { if (error.getError() == GL_CONTEXT_LOST) { if (isContextRobust) m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "No context reset should of occurred GL_CONTEXT_ROBUST_ACCESS == TRUE"); else passAndLog(contextReset); } else if (isContextRobust) m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unknown error."); else { m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Warning: glGetError() returned wrong value. Expected GL_CONTEXT_LOST"); m_testCtx.getLog() << tcu::TestLog::Message << "Warning: glGetError() returned wrong value [" << error.what() << ", expected " << glu::getErrorStr(GL_CONTEXT_LOST) << "]" << tcu::TestLog::EndMessage; } } } else DE_FATAL("Unknown context reset type"); } class BasicResetCase : public ContextResetCase { public: BasicResetCase (EglTestContext& eglTestCtx, const char* name, const char* description, Params params) : ContextResetCase (eglTestCtx, name, description, params) {} virtual void provokeReset (de::SharedPtr& contextReset) { m_testCtx.getLog() << tcu::TestLog::Message << "Check the graphics reset status returned by glGetGraphicsResetStatus() equals " << "GL_GUILTY_CONTEXT_RESET after a context reset\n\n" << tcu::TestLog::EndMessage; contextReset->setup(); contextReset->draw(); } virtual void waitForReset (de::SharedPtr& contextReset) { contextReset->teardown(); contextReset->finish(); } virtual void passAndLog (de::SharedPtr& contextReset) { const glw::GLint status = contextReset->getGraphicsResetStatus(); if (status == GL_NO_ERROR) { m_testCtx.getLog() << tcu::TestLog::Message << "Test failed! glGetGraphicsResetStatus() returned wrong value [" << glu::getGraphicsResetStatusStr(status) << ", expected " << glu::getGraphicsResetStatusStr(GL_GUILTY_CONTEXT_RESET) << "]" << tcu::TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } else { if (contextReset->getError() != GL_NO_ERROR) m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Error flag not reset after calling getGraphicsResetStatus()"); else m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } } }; class InvalidShareContextCase : public RobustnessTestCase { public: InvalidShareContextCase (EglTestContext& eglTestCtx, const char* name, const char* description) : RobustnessTestCase (eglTestCtx, name, description) {} TestCase::IterateResult iterate (void) { TestLog& log = m_testCtx.getLog(); const Library& egl = m_eglTestCtx.getLibrary(); bool isOk = true; log << tcu::TestLog::Message << "EGL_BAD_MATCH is generated if reset notification strategies do not match when creating shared contexts\n\n" << tcu::TestLog::EndMessage; const EGLint attribListA[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 0, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_TRUE, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_NO_RESET_NOTIFICATION, EGL_NONE }; const EGLint attribListB[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 0, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_TRUE, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_LOSE_CONTEXT_ON_RESET, EGL_NONE }; checkRequiredEGLExtensions(attribListA); log << tcu::TestLog::Message << "Create context A (share_context = EGL_NO_CONTEXT)" << tcu::TestLog::EndMessage; RenderingContext contextA(m_eglTestCtx, attribListA, m_eglConfig, m_eglDisplay, EGL_NO_CONTEXT); log << tcu::TestLog::Message << "Create context B (share_context = context A)" << tcu::TestLog::EndMessage; logAttribList(m_eglTestCtx, attribListB); EGLContext contextB = egl.createContext(m_eglDisplay, m_eglConfig, contextA.getContext(), attribListB); const EGLenum error = egl.getError(); if (error != EGL_BAD_MATCH) { log << TestLog::Message << "Test failed! eglCreateContext() returned with error [" << eglu::getErrorStr(error) << ", expected " << eglu::getErrorStr(EGL_BAD_MATCH) << "]" << TestLog::EndMessage; isOk = false; } if (contextB != EGL_NO_CONTEXT) egl.destroyContext(m_eglDisplay, contextB); if (isOk) m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); else m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); return STOP; } }; class InvalidNotificationEnumCase : public RobustnessTestCase { public: InvalidNotificationEnumCase (EglTestContext& eglTestCtx, const char* name, const char* description) : RobustnessTestCase (eglTestCtx, name, description) {} TestCase::IterateResult iterate (void) { TestLog& log = m_testCtx.getLog(); const Library& egl = m_eglTestCtx.getLibrary(); bool isOk = true; log << tcu::TestLog::Message << "EGL_BAD_ATTRIBUTE is generated if EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR is used with EGL versions <= 1.4\n\n" << tcu::TestLog::EndMessage; const EGLint attribList[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 1, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_NO_RESET_NOTIFICATION, EGL_NONE }; if (eglu::getVersion(egl, m_eglDisplay) >= eglu::Version(1, 5)) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test requires EGL version to be under 1.5"); return STOP; } logAttribList(m_eglTestCtx, attribList); EGLContext context = egl.createContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, attribList); const EGLenum error = egl.getError(); if (error != EGL_BAD_ATTRIBUTE) { log << TestLog::Message << "Test failed! eglCreateContext() returned with error [" << eglu::getErrorStr(error) << ", expected " << eglu::getErrorStr(EGL_BAD_ATTRIBUTE) << "]" << TestLog::EndMessage; isOk = false; } if (context != EGL_NO_CONTEXT) egl.destroyContext(m_eglDisplay, context); if (isOk) m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); else m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); return STOP; } }; class InvalidContextCase : public RobustnessTestCase { public: InvalidContextCase (EglTestContext& eglTestCtx, const char* name, const char* description) : RobustnessTestCase (eglTestCtx, name, description) {} TestCase::IterateResult iterate (void) { const Library& egl = m_eglTestCtx.getLibrary(); TestLog& log = m_testCtx.getLog(); bool isOk = true; log << tcu::TestLog::Message << "EGL_BAD_ATTRIBUTE is generated if EXT_create_context_robustness is NOT supported but EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT is specified\n\n" << tcu::TestLog::EndMessage; const EGLint attribList[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 0, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_LOSE_CONTEXT_ON_RESET, EGL_NONE }; if (eglu::hasExtension(egl, m_eglDisplay, "EGL_EXT_create_context_robustness")) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test requires EGL_EXT_create_context_robustness to be unsupported"); return STOP; } logAttribList(m_eglTestCtx, attribList); EGLContext context = egl.createContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, attribList); const EGLenum error = egl.getError(); if (error != EGL_BAD_ATTRIBUTE) { log << TestLog::Message << "Test failed! eglCreateContext() returned with error [" << eglu::getErrorStr(error) << ", expected " << eglu::getErrorStr(EGL_BAD_ATTRIBUTE) << "]" << TestLog::EndMessage; isOk = false; } if (context != EGL_NO_CONTEXT) egl.destroyContext(m_eglDisplay, context); if (isOk) m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); else m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); return STOP; } }; } // anonymous // Note: Tests limited to openGLES 3.1 contexts only TestCaseGroup* createRobustnessTests (EglTestContext& eglTestCtx) { de::MovePtr group (new TestCaseGroup(eglTestCtx, "robustness", "KHR_robustness tests")); tcu::TestCaseGroup* const contextCreationTestGroup = new TestCaseGroup(eglTestCtx, "create_context", "Test valid context_creation attributes"); tcu::TestCaseGroup* const contextResetTestGroup = new TestCaseGroup(eglTestCtx, "reset_context", "Test context resets scenarios"); tcu::TestCaseGroup* const negativeContextTestGroup = new TestCaseGroup(eglTestCtx, "negative_context", "Test invalid context creation attributes"); tcu::TestCaseGroup* const shadersTestGroup = new TestCaseGroup(eglTestCtx, "shaders", "Shader specific context reset tests"); tcu::TestCaseGroup* const fixedFunctionTestGroup = new TestCaseGroup(eglTestCtx, "fixed_function_pipeline", "Fixed function pipeline context reset tests with robust context"); tcu::TestCaseGroup* const fixedFunctionNonRobustTestGroup = new TestCaseGroup(eglTestCtx, "fixed_function_pipeline_non_robust", "Fixed function pipeline context reset tests with non-robust context"); tcu::TestCaseGroup* const outOfBoundsTestGroup = new TestCaseGroup(eglTestCtx, "out_of_bounds", "Out of bounds access scenarios with robust context"); tcu::TestCaseGroup* const outOfBoundsNonRobustTestGroup = new TestCaseGroup(eglTestCtx, "out_of_bounds_non_robust", "Out of bounds access scenarios with non-robust context"); const string resetScenarioDescription = "query error states and reset notifications"; // out-of-bounds test cases { // robust context tcu::TestCaseGroup* const uboReadArrayResetTestGroup = new TestCaseGroup(eglTestCtx, "uniform_block", "Uniform Block Accesses"); tcu::TestCaseGroup* const uboWriteArrayResetTestGroup = new TestCaseGroup(eglTestCtx, "uniform_block", "Uniform Block Accesses"); tcu::TestCaseGroup* const ssboWriteArrayResetTestGroup = new TestCaseGroup(eglTestCtx, "shader_storage_block", "Shader Storage Block accesses"); tcu::TestCaseGroup* const ssboReadArrayResetTestGroup = new TestCaseGroup(eglTestCtx, "shader_storage_block", "Shader Storage Block accesses"); tcu::TestCaseGroup* const localWriteArrayResetTestGroup = new TestCaseGroup(eglTestCtx, "local_array", "Local array accesses"); tcu::TestCaseGroup* const localReadArrayResetTestGroup = new TestCaseGroup(eglTestCtx, "local_array", "Local array accesses"); // non-robust context (internal use only) tcu::TestCaseGroup* const uboReadArrayResetNonRobustTestGroup = new TestCaseGroup(eglTestCtx, "uniform_block", "Uniform Block Accesses"); tcu::TestCaseGroup* const uboWriteArrayResetNonRobustTestGroup = new TestCaseGroup(eglTestCtx, "uniform_block", "Uniform Block Accesses"); tcu::TestCaseGroup* const ssboWriteArrayResetNonRobustTestGroup = new TestCaseGroup(eglTestCtx, "shader_storage_block", "Shader Storage Block accesses"); tcu::TestCaseGroup* const ssboReadArrayResetNonRobustTestGroup = new TestCaseGroup(eglTestCtx, "shader_storage_block", "Shader Storage Block accesses"); tcu::TestCaseGroup* const localWriteArrayResetNonRobustTestGroup = new TestCaseGroup(eglTestCtx, "local_array", "Local array accesses"); tcu::TestCaseGroup* const localReadArrayResetNonRobustTestGroup = new TestCaseGroup(eglTestCtx, "local_array", "Local array accesses"); static const RobustnessTestCase::Params s_outOfBoundReadCases[] = { // ubo read only RobustnessTestCase::Params ("vertex", "Provoke a context reset in vertex shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT, RESOURCETYPE_UBO, READWRITETYPE_READ), RobustnessTestCase::Params ("fragment", "Provoke a context reset in fragment shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_FRAG, RESOURCETYPE_UBO, READWRITETYPE_READ), RobustnessTestCase::Params ("vertex_and_fragment", "Provoke a context reset in vertex and fragment shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT_AND_FRAG, RESOURCETYPE_UBO, READWRITETYPE_READ), RobustnessTestCase::Params ("compute", "Provoke a context reset in compute shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_COMPUTE, RESOURCETYPE_UBO, READWRITETYPE_READ), // ssbo read only RobustnessTestCase::Params ("vertex", "Provoke a context reset in vertex shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT, RESOURCETYPE_SSBO, READWRITETYPE_READ), RobustnessTestCase::Params ("fragment", "Provoke a context reset in fragment shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_FRAG, RESOURCETYPE_SSBO, READWRITETYPE_READ), RobustnessTestCase::Params ("vertex_and_fragment", "Provoke a context reset in vertex and fragment shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT_AND_FRAG, RESOURCETYPE_SSBO, READWRITETYPE_READ), RobustnessTestCase::Params ("compute", "Provoke a context reset in compute shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_COMPUTE, RESOURCETYPE_SSBO, READWRITETYPE_READ), // local array read only RobustnessTestCase::Params ("vertex", "Provoke a context reset in vertex shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_READ), RobustnessTestCase::Params ("fragment", "Provoke a context reset in fragment shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_FRAG, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_READ), RobustnessTestCase::Params ("vertex_and_fragment", "Provoke a context reset in vertex and fragment shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT_AND_FRAG, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_READ), RobustnessTestCase::Params ("compute", "Provoke a context reset in compute shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_COMPUTE, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_READ), // ubo read only (non-robust) RobustnessTestCase::Params ("vertex", "Provoke a context reset in vertex shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT, RESOURCETYPE_UBO, READWRITETYPE_READ), RobustnessTestCase::Params ("fragment", "Provoke a context reset in fragment shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_FRAG, RESOURCETYPE_UBO, READWRITETYPE_READ), RobustnessTestCase::Params ("vertex_and_fragment", "Provoke a context reset in vertex and fragment shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT_AND_FRAG, RESOURCETYPE_UBO, READWRITETYPE_READ), RobustnessTestCase::Params ("compute", "Provoke a context reset in compute shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_COMPUTE, RESOURCETYPE_UBO, READWRITETYPE_READ), // ssbo read only (non-robust) RobustnessTestCase::Params ("vertex", "Provoke a context reset in vertex shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT, RESOURCETYPE_SSBO, READWRITETYPE_READ), RobustnessTestCase::Params ("fragment", "Provoke a context reset in fragment shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_FRAG, RESOURCETYPE_SSBO, READWRITETYPE_READ), RobustnessTestCase::Params ("vertex_and_fragment", "Provoke a context reset in vertex and fragment shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT_AND_FRAG, RESOURCETYPE_SSBO, READWRITETYPE_READ), RobustnessTestCase::Params ("compute", "Provoke a context reset in compute shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_COMPUTE, RESOURCETYPE_SSBO, READWRITETYPE_READ), // local array read only (non-robust) RobustnessTestCase::Params ("vertex", "Provoke a context reset in vertex shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_READ), RobustnessTestCase::Params ("fragment", "Provoke a context reset in fragment shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_FRAG, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_READ), RobustnessTestCase::Params ("vertex_and_fragment", "Provoke a context reset in vertex and fragment shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT_AND_FRAG, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_READ), RobustnessTestCase::Params ("compute", "Provoke a context reset in compute shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_COMPUTE, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_READ), }; for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(s_outOfBoundReadCases); ++testNdx) { const RobustnessTestCase::Params& test = s_outOfBoundReadCases[testNdx]; if (test.getResourceType() == RESOURCETYPE_UBO && test.getRobustAccessType() == ROBUSTACCESS_TRUE) uboReadArrayResetTestGroup->addChild (new BasicResetCase(eglTestCtx, test.getName().c_str(), (test.getDescription() + resetScenarioDescription).c_str(), test)); if (test.getResourceType() == RESOURCETYPE_UBO && test.getRobustAccessType() == ROBUSTACCESS_FALSE) uboReadArrayResetNonRobustTestGroup->addChild (new BasicResetCase(eglTestCtx, test.getName().c_str(), (test.getDescription() + resetScenarioDescription).c_str(), test)); if (test.getResourceType() == RESOURCETYPE_SSBO && test.getRobustAccessType() == ROBUSTACCESS_TRUE) ssboReadArrayResetTestGroup->addChild (new BasicResetCase(eglTestCtx, test.getName().c_str(), (test.getDescription() + resetScenarioDescription).c_str(), test)); if (test.getResourceType() == RESOURCETYPE_SSBO && test.getRobustAccessType() == ROBUSTACCESS_FALSE) ssboReadArrayResetNonRobustTestGroup->addChild (new BasicResetCase(eglTestCtx, test.getName().c_str(), (test.getDescription() + resetScenarioDescription).c_str(), test)); if (test.getResourceType() == RESOURCETYPE_LOCAL_ARRAY && test.getRobustAccessType() == ROBUSTACCESS_TRUE) localReadArrayResetTestGroup->addChild (new BasicResetCase(eglTestCtx, test.getName().c_str(), (test.getDescription() + resetScenarioDescription).c_str(), test)); if (test.getResourceType() == RESOURCETYPE_LOCAL_ARRAY && test.getRobustAccessType() == ROBUSTACCESS_FALSE) localReadArrayResetNonRobustTestGroup->addChild (new BasicResetCase(eglTestCtx, test.getName().c_str(), (test.getDescription() + resetScenarioDescription).c_str(), test)); } static const RobustnessTestCase::Params s_outOfBoundWriteCases[] = { // ubo write only RobustnessTestCase::Params ("vertex", "Provoke a context reset in vertex shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT, RESOURCETYPE_UBO, READWRITETYPE_WRITE), RobustnessTestCase::Params ("fragment", "Provoke a context reset in fragment shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_FRAG, RESOURCETYPE_UBO, READWRITETYPE_WRITE), RobustnessTestCase::Params ("vertex_and_fragment", "Provoke a context reset in vertex and fragment shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT_AND_FRAG, RESOURCETYPE_UBO, READWRITETYPE_WRITE), RobustnessTestCase::Params ("compute", "Provoke a context reset in compute shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_COMPUTE, RESOURCETYPE_UBO, READWRITETYPE_WRITE), // ssbo write only RobustnessTestCase::Params ("vertex", "Provoke a context reset in vertex shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT, RESOURCETYPE_SSBO, READWRITETYPE_WRITE), RobustnessTestCase::Params ("fragment", "Provoke a context reset in fragment shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_FRAG, RESOURCETYPE_SSBO, READWRITETYPE_WRITE), RobustnessTestCase::Params ("vertex_and_fragment", "Provoke a context reset in vertex and fragment shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT_AND_FRAG, RESOURCETYPE_SSBO, READWRITETYPE_WRITE), RobustnessTestCase::Params ("compute", "Provoke a context reset in compute shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_COMPUTE, RESOURCETYPE_SSBO, READWRITETYPE_WRITE), // local array write only RobustnessTestCase::Params ("vertex", "Provoke a context reset in vertex shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_WRITE), RobustnessTestCase::Params ("fragment", "Provoke a context reset in fragment shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_FRAG, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_WRITE), RobustnessTestCase::Params ("vertex_and_fragment", "Provoke a context reset in vertex and fragment shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT_AND_FRAG, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_WRITE), RobustnessTestCase::Params ("compute", "Provoke a context reset in compute shader and ", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_COMPUTE, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_WRITE), // ubo write only (non-robust) RobustnessTestCase::Params ("vertex", "Provoke a context reset in vertex shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT, RESOURCETYPE_UBO, READWRITETYPE_WRITE), RobustnessTestCase::Params ("fragment", "Provoke a context reset in fragment shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_FRAG, RESOURCETYPE_UBO, READWRITETYPE_WRITE), RobustnessTestCase::Params ("vertex_and_fragment", "Provoke a context reset in vertex and fragment shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT_AND_FRAG, RESOURCETYPE_UBO, READWRITETYPE_WRITE), RobustnessTestCase::Params ("compute", "Provoke a context reset in compute shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_COMPUTE, RESOURCETYPE_UBO, READWRITETYPE_WRITE), // ssbo write only (non-robust) RobustnessTestCase::Params ("vertex", "Provoke a context reset in vertex shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT, RESOURCETYPE_SSBO, READWRITETYPE_WRITE), RobustnessTestCase::Params ("fragment", "Provoke a context reset in fragment shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_FRAG, RESOURCETYPE_SSBO, READWRITETYPE_WRITE), RobustnessTestCase::Params ("vertex_and_fragment", "Provoke a context reset in vertex and fragment shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT_AND_FRAG, RESOURCETYPE_SSBO, READWRITETYPE_WRITE), RobustnessTestCase::Params ("compute", "Provoke a context reset in compute shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_COMPUTE, RESOURCETYPE_SSBO, READWRITETYPE_WRITE), // local array write only (non-robust) RobustnessTestCase::Params ("vertex", "Provoke a context reset in vertex shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_WRITE), RobustnessTestCase::Params ("fragment", "Provoke a context reset in fragment shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_FRAG, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_WRITE), RobustnessTestCase::Params ("vertex_and_fragment", "Provoke a context reset in vertex and fragment shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_VERT_AND_FRAG, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_WRITE), RobustnessTestCase::Params ("compute", "Provoke a context reset in compute shader and ", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_SHADER_OOB, SHADERTYPE_COMPUTE, RESOURCETYPE_LOCAL_ARRAY, READWRITETYPE_WRITE), }; for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(s_outOfBoundWriteCases); ++testNdx) { const RobustnessTestCase::Params& test = s_outOfBoundWriteCases[testNdx]; if (test.getResourceType() == RESOURCETYPE_UBO && test.getRobustAccessType() == ROBUSTACCESS_TRUE) uboWriteArrayResetTestGroup->addChild (new BasicResetCase(eglTestCtx, test.getName().c_str(), (test.getDescription() + resetScenarioDescription).c_str(), test)); if (test.getResourceType() == RESOURCETYPE_UBO && test.getRobustAccessType() == ROBUSTACCESS_FALSE) uboWriteArrayResetNonRobustTestGroup->addChild (new BasicResetCase(eglTestCtx, test.getName().c_str(), (test.getDescription() + resetScenarioDescription).c_str(), test)); if (test.getResourceType() == RESOURCETYPE_SSBO && test.getRobustAccessType() == ROBUSTACCESS_TRUE) ssboWriteArrayResetTestGroup->addChild (new BasicResetCase(eglTestCtx, test.getName().c_str(), (test.getDescription() + resetScenarioDescription).c_str(), test)); if (test.getResourceType() == RESOURCETYPE_SSBO && test.getRobustAccessType() == ROBUSTACCESS_FALSE) ssboWriteArrayResetNonRobustTestGroup->addChild (new BasicResetCase(eglTestCtx, test.getName().c_str(), (test.getDescription() + resetScenarioDescription).c_str(), test)); if (test.getResourceType() == RESOURCETYPE_LOCAL_ARRAY && test.getRobustAccessType() == ROBUSTACCESS_TRUE) localWriteArrayResetTestGroup->addChild (new BasicResetCase(eglTestCtx, test.getName().c_str(), (test.getDescription() + resetScenarioDescription).c_str(), test)); if (test.getResourceType() == RESOURCETYPE_LOCAL_ARRAY && test.getRobustAccessType() == ROBUSTACCESS_FALSE) localWriteArrayResetNonRobustTestGroup->addChild (new BasicResetCase(eglTestCtx, test.getName().c_str(), (test.getDescription() + resetScenarioDescription).c_str(), test)); } // robust Context tcu::TestCaseGroup* const outOfBoundsResetReadAccessTestGroup = new TestCaseGroup(eglTestCtx, "reads", "Out of bounds read accesses"); tcu::TestCaseGroup* const outOfBoundsResetWriteAccessTestGroup = new TestCaseGroup(eglTestCtx, "writes", "Out of bounds write accesses"); outOfBoundsResetReadAccessTestGroup->addChild(uboReadArrayResetTestGroup); outOfBoundsResetReadAccessTestGroup->addChild(ssboReadArrayResetTestGroup); outOfBoundsResetReadAccessTestGroup->addChild(localReadArrayResetTestGroup); outOfBoundsResetWriteAccessTestGroup->addChild(uboWriteArrayResetTestGroup); outOfBoundsResetWriteAccessTestGroup->addChild(ssboWriteArrayResetTestGroup); outOfBoundsResetWriteAccessTestGroup->addChild(localWriteArrayResetTestGroup); tcu::TestCaseGroup* const outOfBoundsResetTestGroup = new TestCaseGroup(eglTestCtx, "reset_status", "Tests that query the reset status after a context reset has occurred"); outOfBoundsResetTestGroup->addChild(outOfBoundsResetReadAccessTestGroup); outOfBoundsResetTestGroup->addChild(outOfBoundsResetWriteAccessTestGroup); outOfBoundsTestGroup->addChild(outOfBoundsResetTestGroup); // non-robust Context (internal use only) tcu::TestCaseGroup* const outOfBoundsResetReadAccessNonRobustTestGroup = new TestCaseGroup(eglTestCtx, "reads", "Out of bounds read accesses"); tcu::TestCaseGroup* const outOfBoundsResetWriteAccessNonRobustTestGroup = new TestCaseGroup(eglTestCtx, "writes", "Out of bounds write accesses"); outOfBoundsResetReadAccessNonRobustTestGroup->addChild(uboReadArrayResetNonRobustTestGroup); outOfBoundsResetReadAccessNonRobustTestGroup->addChild(ssboReadArrayResetNonRobustTestGroup); outOfBoundsResetReadAccessNonRobustTestGroup->addChild(localReadArrayResetNonRobustTestGroup); outOfBoundsResetWriteAccessNonRobustTestGroup->addChild(uboWriteArrayResetNonRobustTestGroup); outOfBoundsResetWriteAccessNonRobustTestGroup->addChild(ssboWriteArrayResetNonRobustTestGroup); outOfBoundsResetWriteAccessNonRobustTestGroup->addChild(localWriteArrayResetNonRobustTestGroup); tcu::TestCaseGroup* const outOfBoundsResetNonRobustTestGroup = new TestCaseGroup(eglTestCtx, "reset_status", "Tests that query the reset status after a context reset has occurred"); outOfBoundsResetNonRobustTestGroup->addChild(outOfBoundsResetReadAccessNonRobustTestGroup); outOfBoundsResetNonRobustTestGroup->addChild(outOfBoundsResetWriteAccessNonRobustTestGroup); outOfBoundsNonRobustTestGroup->addChild(outOfBoundsResetNonRobustTestGroup); } // fixed function test cases { // robust context tcu::TestCaseGroup* const fixedFunctionResetStatusTestGroup = new TestCaseGroup(eglTestCtx, "reset_status", "Tests that query the reset status after a context reset has occurred"); // non-robust context (internal use only) tcu::TestCaseGroup* const fixedFunctionResetStatusNonRobustTestGroup = new TestCaseGroup(eglTestCtx, "reset_status", "Tests that query the reset status after a context reset has occurred"); static const RobustnessTestCase::Params s_fixedFunctionPipelineCases[] = { RobustnessTestCase::Params( "index_buffer_out_of_bounds", "Provoke context reset and query error states and reset notifications", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_FIXED_FUNC_OOB, FIXEDFUNCTIONTYPE_INDICES), RobustnessTestCase::Params( "vertex_buffer_out_of_bounds", "Provoke context reset and query error states and reset notifications", ROBUSTACCESS_TRUE, CONTEXTRESETTYPE_FIXED_FUNC_OOB, FIXEDFUNCTIONTYPE_VERTICES), RobustnessTestCase::Params( "index_buffer_out_of_bounds", "Provoke context reset and query error states and reset notifications", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_FIXED_FUNC_OOB, FIXEDFUNCTIONTYPE_INDICES), RobustnessTestCase::Params( "vertex_buffer_out_of_bounds", "Provoke context reset and query error states and reset notifications", ROBUSTACCESS_FALSE, CONTEXTRESETTYPE_FIXED_FUNC_OOB, FIXEDFUNCTIONTYPE_VERTICES), }; for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(s_fixedFunctionPipelineCases); ++testNdx) { const RobustnessTestCase::Params& test = s_fixedFunctionPipelineCases[testNdx]; if (test.getRobustAccessType() == ROBUSTACCESS_TRUE) fixedFunctionResetStatusTestGroup->addChild(new BasicResetCase(eglTestCtx, test.getName().c_str(), test.getDescription().c_str(), test)); else fixedFunctionResetStatusNonRobustTestGroup->addChild(new BasicResetCase(eglTestCtx, test.getName().c_str(), test.getDescription().c_str(), test)); } fixedFunctionTestGroup->addChild(fixedFunctionResetStatusTestGroup); fixedFunctionNonRobustTestGroup->addChild(fixedFunctionResetStatusNonRobustTestGroup); } // context creation query cases { contextCreationTestGroup->addChild(new QueryRobustAccessCase (eglTestCtx, "query_robust_access", "Query robust access after successfully creating a robust context")); contextCreationTestGroup->addChild(new NoResetNotificationCase (eglTestCtx, "no_reset_notification", "Query reset notification strategy after specifying GL_NO_RESET_NOTIFICATION")); contextCreationTestGroup->addChild(new LoseContextOnResetCase (eglTestCtx, "lose_context_on_reset", "Query reset notification strategy after specifying GL_LOSE_CONTEXT_ON_RESET")); } // invalid context creation cases { negativeContextTestGroup->addChild(new InvalidContextCase (eglTestCtx, "invalid_robust_context_creation", "Create a non-robust context but specify a reset notification strategy")); negativeContextTestGroup->addChild(new InvalidShareContextCase (eglTestCtx, "invalid_robust_shared_context_creation", "Create a context share group with conflicting reset notification strategies")); negativeContextTestGroup->addChild(new InvalidNotificationEnumCase (eglTestCtx, "invalid_notification_strategy_enum", "Create a robust context using EGL 1.5 only enum with EGL versions <= 1.4" )); } shadersTestGroup->addChild(outOfBoundsTestGroup); shadersTestGroup->addChild(outOfBoundsNonRobustTestGroup); contextResetTestGroup->addChild(shadersTestGroup); contextResetTestGroup->addChild(fixedFunctionTestGroup); contextResetTestGroup->addChild(fixedFunctionNonRobustTestGroup); group->addChild(contextCreationTestGroup); group->addChild(contextResetTestGroup); group->addChild(negativeContextTestGroup); return group.release(); } } // egl } // deqp