| /*------------------------------------------------------------------------- |
| * 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 <set> |
| |
| 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 <deUint32 Type> |
| 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<EGL_OPENGL_ES2_BIT>; |
| case EGL_OPENGL_ES3_BIT: return renderable<EGL_OPENGL_ES3_BIT>; |
| case EGL_OPENGL_BIT: return renderable<EGL_OPENGL_BIT>; |
| 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 "<Unknown>"; |
| } |
| } |
| |
| 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<string> requiredExtensions; |
| vector<string> 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<string>::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<glw::GLuint> 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<tcu::Vec4> 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<ContextReset> contextResetFactory (const RobustnessTestCase::Params params, glw::Functions& gl, tcu::TestLog& log) |
| { |
| if (params.getContextResetType() == CONTEXTRESETTYPE_FIXED_FUNC_OOB) |
| return de::SharedPtr<ContextReset>(new FixedFunctionOOB(gl, log, params.getFixedFunctionType())); |
| |
| if (params.getContextResetType() == CONTEXTRESETTYPE_SHADER_OOB) |
| return de::SharedPtr<ContextReset>(new ShadersOOB(gl, log, params.getShaderType(), params.getResourceType(), params.getReadWriteType())); |
| else |
| { |
| DE_FATAL("Unknown context reset type"); |
| return de::SharedPtr<ContextReset>(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>& contextReset) = 0; |
| virtual void waitForReset (de::SharedPtr<ContextReset>& contextReset) = 0; |
| virtual void passAndLog (de::SharedPtr<ContextReset>& 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> 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>& 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) |
| { |
| contextReset->teardown(); |
| contextReset->finish(); |
| } |
| |
| virtual void passAndLog (de::SharedPtr<ContextReset>& 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<TestCaseGroup> 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 |