You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2504 lines
91 KiB
2504 lines
91 KiB
/*-------------------------------------------------------------------------
|
|
* 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_INFINITE_LOOP,
|
|
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 ContextResetType& contextResetType,
|
|
const ShaderType& shaderType);
|
|
|
|
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 ContextResetType& contextResetType,
|
|
const ShaderType& shaderType)
|
|
: m_name (name)
|
|
, m_description (description)
|
|
, m_contextResetType (contextResetType)
|
|
, m_shaderType (shaderType)
|
|
{
|
|
}
|
|
|
|
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);
|
|
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);
|
|
void createSyncObject (void);
|
|
glw::GLint getSyncStatus (void);
|
|
|
|
void beginQuery (void);
|
|
void endQuery (void);
|
|
glw::GLint getError (void);
|
|
glw::GLint getGraphicsResetStatus (void);
|
|
glw::GLuint getQueryAvailability (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)
|
|
{
|
|
}
|
|
|
|
ContextReset::ContextReset (glw::Functions& gl, tcu::TestLog& log, ShaderType shaderType)
|
|
: m_gl (gl)
|
|
, m_log (log)
|
|
, m_shaderType (shaderType)
|
|
{
|
|
}
|
|
|
|
void ContextReset::finish (void)
|
|
{
|
|
GLU_CHECK_GLW_CALL(m_gl, finish());
|
|
}
|
|
|
|
void ContextReset::createSyncObject (void)
|
|
{
|
|
m_sync = m_gl.fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
GLU_EXPECT_NO_ERROR(m_gl.getError(), "glFenceSync()");
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
glw::GLint ContextReset::getSyncStatus (void)
|
|
{
|
|
glw::GLint syncStatus;
|
|
m_gl.getSynciv(m_sync, GL_SYNC_STATUS, sizeof(glw::GLint), NULL, &syncStatus);
|
|
|
|
return syncStatus;
|
|
}
|
|
|
|
void ContextReset::beginQuery (void)
|
|
{
|
|
GLU_CHECK_GLW_CALL(m_gl, genQueries(1, &m_queryID));
|
|
GLU_CHECK_GLW_CALL(m_gl, beginQuery(GL_ANY_SAMPLES_PASSED, m_queryID));
|
|
}
|
|
|
|
void ContextReset::endQuery (void)
|
|
{
|
|
GLU_CHECK_GLW_CALL(m_gl, endQuery(GL_ANY_SAMPLES_PASSED));
|
|
}
|
|
|
|
glw::GLuint ContextReset::getQueryAvailability (void)
|
|
{
|
|
glw::GLuint queryReady = GL_FALSE;
|
|
m_gl.getQueryObjectuiv(m_queryID, GL_QUERY_RESULT_AVAILABLE, &queryReady);
|
|
|
|
return queryReady;
|
|
}
|
|
|
|
class InfiniteLoop : public ContextReset
|
|
{
|
|
public:
|
|
InfiniteLoop (glw::Functions& gl, tcu::TestLog& log, ShaderType shaderType);
|
|
~InfiniteLoop (void);
|
|
|
|
virtual void setup (void);
|
|
virtual void draw (void);
|
|
virtual void teardown (void);
|
|
|
|
private:
|
|
glu::ProgramSources genComputeSource (void);
|
|
glu::ProgramSources genNonComputeSource (void);
|
|
glu::ProgramSources genSources (void);
|
|
|
|
glw::GLuint m_outputBuffer;
|
|
glw::GLuint m_coordinatesBuffer;
|
|
glw::GLint m_coordLocation;
|
|
};
|
|
|
|
InfiniteLoop::InfiniteLoop (glw::Functions& gl, tcu::TestLog& log, ShaderType shaderType)
|
|
: ContextReset(gl, log, shaderType)
|
|
, m_outputBuffer (0)
|
|
, m_coordinatesBuffer (0)
|
|
, m_coordLocation (0)
|
|
{
|
|
}
|
|
|
|
InfiniteLoop::~InfiniteLoop (void)
|
|
{
|
|
try
|
|
{
|
|
// Reset GL_CONTEXT_LOST error before destroying resources
|
|
m_gl.getGraphicsResetStatus();
|
|
teardown();
|
|
}
|
|
catch (...)
|
|
{
|
|
// Ignore GL errors from teardown()
|
|
}
|
|
}
|
|
|
|
glu::ProgramSources InfiniteLoop::genSources(void)
|
|
{
|
|
if (m_shaderType == SHADERTYPE_COMPUTE)
|
|
return genComputeSource();
|
|
else
|
|
return genNonComputeSource();
|
|
}
|
|
|
|
glu::ProgramSources InfiniteLoop::genComputeSource(void)
|
|
{
|
|
const char* const computeSource =
|
|
"#version 310 es\n"
|
|
"layout(local_size_x = 1, local_size_y = 1) in;\n"
|
|
"uniform highp int u_iterCount;\n"
|
|
"writeonly buffer Output { highp int b_output_int; };\n"
|
|
"void main ()\n"
|
|
"{\n"
|
|
" for (highp int i = 0; i < u_iterCount || u_iterCount < 0; ++i)\n"
|
|
" b_output_int = u_iterCount;\n"
|
|
"}\n";
|
|
|
|
return glu::ProgramSources() << glu::ComputeSource(computeSource);
|
|
}
|
|
|
|
glu::ProgramSources InfiniteLoop::genNonComputeSource (void)
|
|
{
|
|
const bool isVertCase = m_shaderType == SHADERTYPE_VERT;
|
|
const bool isFragCase = m_shaderType == SHADERTYPE_FRAG;
|
|
const bool isVertAndFragment = m_shaderType == SHADERTYPE_VERT_AND_FRAG;
|
|
|
|
std::ostringstream vert, frag;
|
|
|
|
vert << "#version 300 es\n"
|
|
<< "in highp vec2 a_position;\n";
|
|
|
|
frag << "#version 300 es\n";
|
|
|
|
vert << "uniform highp int u_iterCount;\n";
|
|
if (isFragCase || isVertAndFragment)
|
|
{
|
|
vert << "flat out highp int v_iterCount;\n";
|
|
frag << "flat in highp int v_iterCount;\n";
|
|
}
|
|
|
|
if (isVertCase || isVertAndFragment)
|
|
{
|
|
vert << "out mediump vec4 v_color;\n";
|
|
frag << "in mediump vec4 v_color;\n";
|
|
}
|
|
|
|
frag << "out mediump vec4 o_color;\n";
|
|
|
|
vert << "\nvoid main (void)\n{\n"
|
|
<< " gl_Position = vec4(a_position, 0.0, 1.0);\n"
|
|
<< " gl_PointSize = 1.0;\n";
|
|
|
|
if (isFragCase || isVertAndFragment)
|
|
vert << " v_iterCount = u_iterCount;\n";
|
|
|
|
frag << "\nvoid main (void)\n{\n";
|
|
|
|
const std::string iterCount = (isVertCase ? "u_iterCount" : "v_iterCount");
|
|
const std::string loopHeader = " for (highp int i = 0; i < " + iterCount + " || " + iterCount + " < 0; ++i)\n";
|
|
const char* const body = "color = cos(sin(color*1.25)*0.8);";
|
|
|
|
if (isVertAndFragment)
|
|
{
|
|
vert << " mediump vec4 color = " << "a_position.xyxy" << ";\n";
|
|
vert << loopHeader << " " << body << "\n";
|
|
|
|
frag << " mediump vec4 color = " << "gl_FragCoord" << ";\n";
|
|
frag << loopHeader << " " << body << "\n";
|
|
}
|
|
else
|
|
{
|
|
std::ostringstream& op = isVertCase ? vert : frag;
|
|
op << " mediump vec4 color = " << (isVertCase ? "a_position.xyxy" : "gl_FragCoord") << ";\n";
|
|
op << loopHeader << " " << body << "\n";
|
|
}
|
|
|
|
if (isVertCase || isVertAndFragment)
|
|
{
|
|
vert << " v_color = color;\n";
|
|
frag << " o_color = v_color;\n";
|
|
}
|
|
else
|
|
frag << " o_color = color;\n";
|
|
|
|
vert << "}\n";
|
|
frag << "}\n";
|
|
|
|
return glu::ProgramSources() << glu::VertexSource(vert.str()) << glu::FragmentSource(frag.str());
|
|
}
|
|
|
|
void InfiniteLoop::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()));
|
|
|
|
if (m_shaderType == SHADERTYPE_COMPUTE)
|
|
{
|
|
// Output buffer setup
|
|
m_outputBuffer = 0;
|
|
GLU_CHECK_GLW_CALL(m_gl, genBuffers(1, &m_outputBuffer));
|
|
GLU_CHECK_GLW_CALL(m_gl, bindBuffer(GL_SHADER_STORAGE_BUFFER, m_outputBuffer));
|
|
GLU_CHECK_GLW_CALL(m_gl, bufferData(GL_SHADER_STORAGE_BUFFER, sizeof(int), DE_NULL, GL_DYNAMIC_DRAW));
|
|
GLU_CHECK_GLW_CALL(m_gl, bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_outputBuffer));
|
|
}
|
|
else
|
|
{
|
|
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));
|
|
}
|
|
|
|
glw::GLint iterCountLocation = m_gl.getUniformLocation(program.getProgram(), "u_iterCount");
|
|
GLU_CHECK_GLW_MSG(m_gl, "glGetUniformLocation()");
|
|
TCU_CHECK(iterCountLocation != (glw::GLint)-1);
|
|
|
|
// Set the iteration count (infinite)
|
|
glw::GLint iterCount = -1;
|
|
GLU_CHECK_GLW_CALL(m_gl, uniform1i(iterCountLocation, iterCount));
|
|
}
|
|
|
|
void InfiniteLoop::draw (void)
|
|
{
|
|
if (m_shaderType == SHADERTYPE_COMPUTE)
|
|
m_gl.dispatchCompute(1, 1, 1);
|
|
else
|
|
{
|
|
const glw::GLushort indices[] = { 0, 1, 2, 2, 3, 0 };
|
|
m_gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
|
|
}
|
|
}
|
|
|
|
void InfiniteLoop::teardown (void)
|
|
{
|
|
if (m_shaderType != SHADERTYPE_COMPUTE)
|
|
{
|
|
if (m_coordLocation)
|
|
{
|
|
GLU_CHECK_GLW_CALL(m_gl, disableVertexAttribArray(m_coordLocation));
|
|
m_coordLocation = 0;
|
|
}
|
|
}
|
|
|
|
if (m_outputBuffer)
|
|
{
|
|
GLU_CHECK_GLW_CALL(m_gl, deleteBuffers(1, &m_outputBuffer));
|
|
m_outputBuffer = 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 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 dummy 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_INFINITE_LOOP)
|
|
return de::SharedPtr<ContextReset>(new InfiniteLoop(gl, log, params.getShaderType()));
|
|
|
|
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_INFINITE_LOOP)
|
|
{
|
|
try
|
|
{
|
|
waitForReset(contextReset);
|
|
|
|
const glw::GLenum status = gl.getGraphicsResetStatus();
|
|
|
|
if (status == GL_NO_ERROR)
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Context was NOT lost");
|
|
else
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::Message << "glGetGraphicsResetStatus() returned " << glu::getGraphicsResetStatusStr(status) << tcu::TestLog::EndMessage;
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Context was lost");
|
|
}
|
|
}
|
|
catch (const glu::Error& error)
|
|
{
|
|
if (error.getError() == GL_CONTEXT_LOST)
|
|
passAndLog(contextReset);
|
|
else
|
|
{
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
|
|
|
|
m_testCtx.getLog() << tcu::TestLog::Message
|
|
<< "Warning: glGetError() returned wrong value [" << error.what() << ", expected " << glu::getErrorStr(GL_CONTEXT_LOST) << "]"
|
|
<< tcu::TestLog::EndMessage;
|
|
}
|
|
}
|
|
}
|
|
else 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 SyncObjectResetCase : public ContextResetCase
|
|
{
|
|
public:
|
|
SyncObjectResetCase (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 status of a sync object after a context reset returned by glGetSynciv() equals GL_SIGNALED\n\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
contextReset->setup();
|
|
contextReset->draw();
|
|
}
|
|
|
|
virtual void waitForReset (de::SharedPtr<ContextReset>& contextReset)
|
|
{
|
|
contextReset->createSyncObject();
|
|
contextReset->teardown();
|
|
contextReset->finish();
|
|
}
|
|
|
|
virtual void passAndLog (de::SharedPtr<ContextReset>& contextReset)
|
|
{
|
|
const glw::GLint status = contextReset->getSyncStatus();
|
|
if (status != GL_SIGNALED)
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::Message
|
|
<< "Test failed! glGetSynciv() returned wrong value [" << glu::getErrorStr(status) << ", expected " << glu::getErrorStr(GL_SIGNALED) << "]"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
|
|
}
|
|
else
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
}
|
|
};
|
|
|
|
class QueryObjectResetCase : public ContextResetCase
|
|
{
|
|
public:
|
|
QueryObjectResetCase (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 status of a query object after a context reset returned by glGetQueryObjectuiv() equals GL_TRUE\n\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
contextReset->setup();
|
|
contextReset->beginQuery();
|
|
contextReset->draw();
|
|
}
|
|
|
|
virtual void waitForReset (de::SharedPtr<ContextReset>& contextReset)
|
|
{
|
|
contextReset->endQuery();
|
|
contextReset->teardown();
|
|
contextReset->finish();
|
|
}
|
|
|
|
virtual void passAndLog (de::SharedPtr<ContextReset>& contextReset)
|
|
{
|
|
const glw::GLuint queryReady = contextReset->getQueryAvailability();
|
|
if (queryReady != GL_TRUE)
|
|
{
|
|
m_testCtx.getLog() << tcu::TestLog::Message
|
|
<< "Test failed! glGetQueryObjectuiv() returned wrong value [" << glu::getErrorStr(queryReady) << ", expected " << glu::getErrorStr(GL_TRUE) << "]"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
|
|
}
|
|
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 SharedContextResetCase : public RobustnessTestCase
|
|
{
|
|
public:
|
|
SharedContextResetCase (EglTestContext& eglTestCtx, const char* name, const char* description, Params params)
|
|
: RobustnessTestCase (eglTestCtx, name, description, params) {}
|
|
|
|
TestCase::IterateResult iterate (void)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
|
|
log << tcu::TestLog::Message
|
|
<< "A reset in one context will result in a reset in all other contexts in its share group\n\n"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
// Create two share contexts with the same reset notification strategies
|
|
const EGLint attribListShared[] =
|
|
{
|
|
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(attribListShared);
|
|
|
|
log << tcu::TestLog::Message << "Create context A (share_context = EGL_NO_CONTEXT)" << tcu::TestLog::EndMessage;
|
|
RenderingContext contextA(m_eglTestCtx, attribListShared, m_eglConfig, m_eglDisplay, EGL_NO_CONTEXT);
|
|
|
|
log << tcu::TestLog::Message << "Create context B (share_context = context A)" << tcu::TestLog::EndMessage;
|
|
RenderingContext contextB(m_eglTestCtx, attribListShared, m_eglConfig, m_eglDisplay, contextA.getContext());
|
|
|
|
contextA.makeCurrent(m_eglSurface);
|
|
|
|
glw::Functions gl;
|
|
contextA.initGLFunctions(&gl, paramsToApiType(m_params));
|
|
checkGLSupportForParams(gl, m_params);
|
|
|
|
DE_ASSERT(m_params.getContextResetType() == CONTEXTRESETTYPE_INFINITE_LOOP);
|
|
de::UniquePtr<ContextReset> contextReset(new InfiniteLoop(gl, log, m_params.getShaderType()));
|
|
|
|
contextReset->setup();
|
|
contextReset->draw();
|
|
|
|
try
|
|
{
|
|
contextReset->teardown();
|
|
contextReset->finish();
|
|
}
|
|
catch (const glu::Error& error)
|
|
{
|
|
if (error.getError() == GL_CONTEXT_LOST)
|
|
{
|
|
contextB.makeCurrent(m_eglSurface);
|
|
|
|
gl.getString(GL_VERSION); // arbitrary gl call
|
|
|
|
if (gl.getError() != GL_CONTEXT_LOST)
|
|
{
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Test failed! glGetError() returned wrong value. Expected GL_CONTEXT_LOST in context B");
|
|
return STOP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Test failed! glGetError() returned wrong value. Expected GL_CONTEXT_LOST in context A");
|
|
return STOP;
|
|
}
|
|
}
|
|
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
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;
|
|
}
|
|
};
|
|
|
|
class RecoverFromResetCase : public RobustnessTestCase
|
|
{
|
|
public:
|
|
RecoverFromResetCase (EglTestContext& eglTestCtx, const char* name, const char* description, Params params)
|
|
: RobustnessTestCase (eglTestCtx, name, description, params) {}
|
|
|
|
TestCase::IterateResult iterate (void)
|
|
{
|
|
TestLog& log = m_testCtx.getLog();
|
|
|
|
log << tcu::TestLog::Message
|
|
<< "Provoke a context reset and wait for glGetGraphicsResetStatus() to return NO_ERROR_KHR.\n"
|
|
<< "Destroy the old context and successfully create a new context.\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);
|
|
|
|
log << tcu::TestLog::Message << "Create context A" << tcu::TestLog::EndMessage;
|
|
RenderingContext contextA(m_eglTestCtx, attribList, m_eglConfig, m_eglDisplay, EGL_NO_CONTEXT);
|
|
contextA.makeCurrent(m_eglSurface);
|
|
|
|
glw::Functions gl;
|
|
contextA.initGLFunctions(&gl, paramsToApiType(m_params));
|
|
checkGLSupportForParams(gl, m_params);
|
|
|
|
DE_ASSERT(m_params.getContextResetType() == CONTEXTRESETTYPE_INFINITE_LOOP);
|
|
de::UniquePtr<ContextReset> contextReset(new InfiniteLoop(gl, log, m_params.getShaderType()));
|
|
|
|
contextReset->setup();
|
|
contextReset->draw();
|
|
|
|
try
|
|
{
|
|
contextReset->teardown();
|
|
contextReset->finish();
|
|
}
|
|
catch (const glu::Error& error)
|
|
{
|
|
if (error.getError() == GL_CONTEXT_LOST)
|
|
{
|
|
const glw::GLint status = gl.getGraphicsResetStatus();
|
|
if (status == GL_NO_ERROR)
|
|
{
|
|
log << tcu::TestLog::Message
|
|
<< "Test failed! glGetGraphicsResetStatus() returned wrong value [" << glu::getErrorStr(status) << ", expected " << glu::getErrorStr(GL_GUILTY_CONTEXT_RESET) << "]"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
|
|
return STOP;
|
|
}
|
|
|
|
const int sleepTimeMs = 1000; // (1 second)
|
|
int timeout = sleepTimeMs * 10; // (10 seconds)
|
|
int reset_status = -1;
|
|
|
|
// wait for context to reset
|
|
while ((reset_status = gl.getGraphicsResetStatus() != GL_NO_ERROR) && timeout > 0)
|
|
{
|
|
deSleep(sleepTimeMs);
|
|
timeout -= sleepTimeMs;
|
|
}
|
|
|
|
if (reset_status != GL_NO_ERROR)
|
|
{
|
|
log << tcu::TestLog::Message
|
|
<< "Test failed! Context did not reset. glGetGraphicsResetStatus() returned wrong value [" << glu::getErrorStr(reset_status) << ", expected " << glu::getErrorStr(GL_NO_ERROR) << "]"
|
|
<< tcu::TestLog::EndMessage;
|
|
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
|
|
return STOP;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Test failed! glGetError() returned wrong value. Expected GL_CONTEXT_LOST in context A");
|
|
return STOP;
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
log << tcu::TestLog::Message << "Create context B" << tcu::TestLog::EndMessage;
|
|
RenderingContext contextB(m_eglTestCtx, attribList, m_eglConfig, m_eglDisplay, EGL_NO_CONTEXT);
|
|
}
|
|
catch (const glu::Error&)
|
|
{
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Test failed! Could not create new context. glGetError() returned wrong value. Expected GL_NO_ERROR");
|
|
return STOP;
|
|
}
|
|
|
|
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
|
|
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 infiniteLoopTestGroup = new TestCaseGroup(eglTestCtx, "infinite_loop", "Infinite loop scenarios");
|
|
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";
|
|
const string syncScenarioDescription = "query sync status with getSynciv()";
|
|
const string queryScenarioDescription = "check availability of query result with getQueryObjectiv()";
|
|
const string sharedScenarioDescription = "check reset notification is propagated to shared context";
|
|
const string recoverScenarioDescription = "delete the old context and create a new one";
|
|
|
|
// infinite loop test cases
|
|
{
|
|
tcu::TestCaseGroup* const infiniteLoopResetTestGroup = new TestCaseGroup(eglTestCtx, "reset_status", "Tests that query the reset status after a context reset has occurred");
|
|
tcu::TestCaseGroup* const infiniteLoopSyncTestGroup = new TestCaseGroup(eglTestCtx, "sync_status", "Tests that query the sync status after a context reset has occurred");
|
|
tcu::TestCaseGroup* const infiniteLoopQueryTestGroup = new TestCaseGroup(eglTestCtx, "query_status", "Tests that query the state of a query object after a context reset has occurred");
|
|
tcu::TestCaseGroup* const infiniteLoopSharedTestGroup = new TestCaseGroup(eglTestCtx, "shared_context_status", "Tests that query the state of a shared context after a reset has occurred");
|
|
tcu::TestCaseGroup* const infiniteLoopRecoverTestGroup = new TestCaseGroup(eglTestCtx, "recover_from_reset", "Tests that attempt to create a new context after a context has occurred");
|
|
|
|
static const RobustnessTestCase::Params s_infiniteLoopCases[] =
|
|
{
|
|
RobustnessTestCase::Params("vertex", "Provoke a context reset in vertex shader and ", CONTEXTRESETTYPE_INFINITE_LOOP, SHADERTYPE_VERT),
|
|
RobustnessTestCase::Params("fragment", "Provoke a context reset in fragment shader and ", CONTEXTRESETTYPE_INFINITE_LOOP, SHADERTYPE_FRAG),
|
|
RobustnessTestCase::Params("vertex_and_fragment", "Provoke a context reset in vertex and fragment shader and ", CONTEXTRESETTYPE_INFINITE_LOOP, SHADERTYPE_VERT_AND_FRAG),
|
|
RobustnessTestCase::Params("compute", "Provoke a context reset in compute shader and ", CONTEXTRESETTYPE_INFINITE_LOOP, SHADERTYPE_COMPUTE),
|
|
};
|
|
|
|
for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(s_infiniteLoopCases); ++testNdx)
|
|
{
|
|
const RobustnessTestCase::Params& test = s_infiniteLoopCases[testNdx];
|
|
infiniteLoopResetTestGroup->addChild (new BasicResetCase (eglTestCtx, test.getName().c_str(), (test.getDescription() + resetScenarioDescription).c_str(), test));
|
|
infiniteLoopSyncTestGroup->addChild (new SyncObjectResetCase (eglTestCtx, test.getName().c_str(), (test.getDescription() + syncScenarioDescription).c_str(), test));
|
|
infiniteLoopQueryTestGroup->addChild (new QueryObjectResetCase (eglTestCtx, test.getName().c_str(), (test.getDescription() + queryScenarioDescription).c_str(), test));
|
|
infiniteLoopSharedTestGroup->addChild (new SharedContextResetCase (eglTestCtx, test.getName().c_str(), (test.getDescription() + sharedScenarioDescription).c_str(), test));
|
|
infiniteLoopRecoverTestGroup->addChild (new RecoverFromResetCase (eglTestCtx, test.getName().c_str(), (test.getDescription() + recoverScenarioDescription).c_str(), test));
|
|
}
|
|
|
|
infiniteLoopTestGroup->addChild(infiniteLoopResetTestGroup);
|
|
infiniteLoopTestGroup->addChild(infiniteLoopSyncTestGroup);
|
|
infiniteLoopTestGroup->addChild(infiniteLoopQueryTestGroup);
|
|
infiniteLoopTestGroup->addChild(infiniteLoopSharedTestGroup);
|
|
infiniteLoopTestGroup->addChild(infiniteLoopRecoverTestGroup);
|
|
}
|
|
|
|
// 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(infiniteLoopTestGroup);
|
|
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
|