Add stubs for no_error extension.

In some cases ANGLE flushes state for FBOs during validation. For
testing of the state synching code for FBOs, this makes end-to-end
testing impossible.

Solve this by partially implementing a hidden no_error extension,
hidden to the user by not exposing the extension string, but allowing
us to skip validation of some of the FBO methods that require checking
for complete FBOs.

BUG=angleproject:1280
BUG=angleproject:1260

Change-Id: I708f348ccec6697b974c48cd890ec75a703abe21
Reviewed-on: https://chromium-review.googlesource.com/322210
Tryjob-Request: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Jamie Madill
2016-01-18 14:42:30 -05:00
parent e5df3066c0
commit 46e6c7a512
22 changed files with 127 additions and 66 deletions

View File

@@ -152,6 +152,7 @@ Extensions::Extensions()
maxDebugLoggedMessages(0),
maxDebugGroupStackDepth(0),
maxLabelLength(0),
noError(false),
colorBufferFloat(false)
{
}
@@ -218,6 +219,8 @@ std::vector<std::string> Extensions::getStrings() const
InsertExtensionString("GL_EXT_color_buffer_float", colorBufferFloat, &extensionStrings);
InsertExtensionString("GL_OES_vertex_array_object", vertexArrayObject, &extensionStrings);
InsertExtensionString("GL_KHR_debug", debug, &extensionStrings);
// TODO(jmadill): Enable this when complete.
//InsertExtensionString("GL_KHR_no_error", noError, &extensionStrings);
// clang-format on
return extensionStrings;
@@ -622,7 +625,8 @@ DisplayExtensions::DisplayExtensions()
glRenderbufferImage(false),
getAllProcAddresses(false),
flexibleSurfaceCompatibility(false),
directComposition(false)
directComposition(false),
createContextNoError(false)
{
}
@@ -652,6 +656,8 @@ std::vector<std::string> DisplayExtensions::getStrings() const
InsertExtensionString("EGL_KHR_gl_renderbuffer_image", glRenderbufferImage, &extensionStrings);
InsertExtensionString("EGL_KHR_get_all_proc_addresses", getAllProcAddresses, &extensionStrings);
InsertExtensionString("EGL_ANGLE_flexible_surface_compatibility", flexibleSurfaceCompatibility, &extensionStrings);
// TODO(jmadill): Enable this when complete.
//InsertExtensionString("KHR_create_context_no_error", createContextNoError, &extensionStrings);
// clang-format on
return extensionStrings;

View File

@@ -267,6 +267,9 @@ struct Extensions
GLuint maxDebugGroupStackDepth;
GLuint maxLabelLength;
// KHR_no_error
bool noError;
// ES3 Extension support
// GL_EXT_color_buffer_float
@@ -468,6 +471,9 @@ struct DisplayExtensions
// EGL_ANGLE_direct_composition
bool directComposition;
// KHR_create_context_no_error
bool createContextNoError;
};
struct DeviceExtensions

View File

@@ -52,37 +52,79 @@ void MarkTransformFeedbackBufferUsage(gl::TransformFeedback *transformFeedback)
}
}
}
// Attribute map queries.
EGLint GetClientVersion(const egl::AttributeMap &attribs)
{
return attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1);
}
GLenum GetResetStrategy(const egl::AttributeMap &attribs)
{
EGLenum attrib = attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT,
EGL_NO_RESET_NOTIFICATION_EXT);
switch (attrib)
{
case EGL_NO_RESET_NOTIFICATION:
return GL_NO_RESET_NOTIFICATION_EXT;
case EGL_LOSE_CONTEXT_ON_RESET:
return GL_LOSE_CONTEXT_ON_RESET_EXT;
default:
UNREACHABLE();
return GL_NONE;
}
}
bool GetRobustAccess(const egl::AttributeMap &attribs)
{
return (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE);
}
bool GetDebug(const egl::AttributeMap &attribs)
{
return (attribs.get(EGL_CONTEXT_OPENGL_DEBUG, EGL_FALSE) == EGL_TRUE);
}
bool GetNoError(const egl::AttributeMap &attribs)
{
return (attribs.get(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, EGL_FALSE) == EGL_TRUE);
}
} // anonymous namespace
namespace gl
{
Context::Context(const egl::Config *config,
int clientVersion,
const Context *shareContext,
rx::Renderer *renderer,
bool notifyResets,
bool robustAccess,
bool debug)
: ValidationContext(clientVersion,
const egl::AttributeMap &attribs)
: ValidationContext(GetClientVersion(attribs),
mState,
mCaps,
mTextureCaps,
mExtensions,
nullptr,
mLimitations),
mLimitations,
GetNoError(attribs)),
mCompiler(nullptr),
mRenderer(renderer),
mClientVersion(GetClientVersion(attribs)),
mConfig(config),
mCurrentSurface(nullptr)
mClientType(EGL_OPENGL_ES_API),
mHasBeenCurrent(false),
mContextLost(false),
mResetStatus(GL_NO_ERROR),
mResetStrategy(GetResetStrategy(attribs)),
mRobustAccess(GetRobustAccess(attribs)),
mCurrentSurface(nullptr),
mResourceManager(nullptr)
{
ASSERT(robustAccess == false); // Unimplemented
ASSERT(!mRobustAccess); // Unimplemented
initCaps(clientVersion);
mState.initialize(mCaps, mExtensions, clientVersion, debug);
initCaps(mClientVersion);
mClientVersion = clientVersion;
mClientType = EGL_OPENGL_ES_API;
mState.initialize(mCaps, mExtensions, mClientVersion, GetDebug(attribs));
mFenceNVHandleAllocator.setBaseHandle(0);
@@ -148,12 +190,6 @@ Context::Context(const egl::Config *config,
bindTransformFeedback(0);
}
mHasBeenCurrent = false;
mContextLost = false;
mResetStatus = GL_NO_ERROR;
mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT);
mRobustAccess = robustAccess;
mCompiler = new Compiler(mRenderer, getData());
}

View File

@@ -33,6 +33,7 @@ class Renderer;
namespace egl
{
class AttributeMap;
class Surface;
struct Config;
}
@@ -59,12 +60,9 @@ class Context final : public ValidationContext
{
public:
Context(const egl::Config *config,
int clientVersion,
const Context *shareContext,
rx::Renderer *renderer,
bool notifyResets,
bool robustAccess,
bool debug);
const egl::AttributeMap &attribs);
virtual ~Context();

View File

@@ -40,7 +40,8 @@ ValidationContext::ValidationContext(GLint clientVersion,
const TextureCapsMap &textureCaps,
const Extensions &extensions,
const ResourceManager *resourceManager,
const Limitations &limitations)
const Limitations &limitations,
bool skipValidation)
: mData(reinterpret_cast<uintptr_t>(this),
clientVersion,
state,
@@ -48,7 +49,8 @@ ValidationContext::ValidationContext(GLint clientVersion,
textureCaps,
extensions,
resourceManager,
limitations)
limitations),
mSkipValidation(skipValidation)
{
}
}
} // namespace gl

View File

@@ -47,7 +47,8 @@ class ValidationContext : angle::NonCopyable
const TextureCapsMap &textureCaps,
const Extensions &extensions,
const ResourceManager *resourceManager,
const Limitations &limitations);
const Limitations &limitations,
bool skipValidation);
virtual ~ValidationContext() {}
virtual void recordError(const Error &error) = 0;
@@ -59,9 +60,11 @@ class ValidationContext : angle::NonCopyable
const TextureCapsMap &getTextureCaps() const { return *mData.textureCaps; }
const Extensions &getExtensions() const { return *mData.extensions; }
const Limitations &getLimitations() const { return *mData.limitations; }
bool skipValidation() const { return mSkipValidation; }
protected:
Data mData;
bool mSkipValidation;
};
}

View File

@@ -695,12 +695,8 @@ Error Display::createContext(const Config *configuration, gl::Context *shareCont
}
}
gl::Context *context = nullptr;
Error error = mImplementation->createContext(configuration, shareContext, attribs, &context);
if (error.isError())
{
return error;
}
gl::Context *context = *outContext =
mImplementation->createContext(configuration, shareContext, attribs);
ASSERT(context != nullptr);
mContextSet.insert(context);

View File

@@ -64,8 +64,9 @@ class DisplayImpl : angle::NonCopyable
egl::ImageSibling *buffer,
const egl::AttributeMap &attribs) = 0;
virtual egl::Error createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs,
gl::Context **outContext) = 0;
virtual gl::Context *createContext(const egl::Config *config,
const gl::Context *shareContext,
const egl::AttributeMap &attribs) = 0;
virtual egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) = 0;

View File

@@ -229,19 +229,12 @@ egl::Error DisplayD3D::getDevice(DeviceImpl **device)
return mRenderer->getEGLDevice(device);
}
egl::Error DisplayD3D::createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs,
gl::Context **outContext)
gl::Context *DisplayD3D::createContext(const egl::Config *config,
const gl::Context *shareContext,
const egl::AttributeMap &attribs)
{
ASSERT(mRenderer != nullptr);
EGLint clientVersion = attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1);
bool notifyResets = (attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_NO_RESET_NOTIFICATION_EXT) == EGL_LOSE_CONTEXT_ON_RESET_EXT);
bool robustAccess = (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE);
bool debug = (attribs.get(EGL_CONTEXT_OPENGL_DEBUG, EGL_FALSE) == EGL_TRUE);
*outContext = new gl::Context(config, clientVersion, shareContext, mRenderer, notifyResets,
robustAccess, debug);
return egl::Error(EGL_SUCCESS);
return new gl::Context(config, shareContext, mRenderer, attribs);
}
egl::Error DisplayD3D::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context)

View File

@@ -41,8 +41,9 @@ class DisplayD3D : public DisplayImpl
egl::ImageSibling *buffer,
const egl::AttributeMap &attribs) override;
egl::Error createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs,
gl::Context **outContext) override;
gl::Context *createContext(const egl::Config *config,
const gl::Context *shareContext,
const egl::AttributeMap &attribs) override;
egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) override;

View File

@@ -1084,6 +1084,8 @@ void Renderer11::generateDisplayExtensions(egl::DisplayExtensions *outExtensions
outExtensions->deviceQuery = true;
outExtensions->createContextNoError = true;
outExtensions->image = true;
outExtensions->imageBase = true;
outExtensions->glTexture2DImage = true;

View File

@@ -1217,6 +1217,7 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons
extensions->unpackSubimage = true;
extensions->packSubimage = true;
extensions->vertexArrayObject = true;
extensions->noError = true;
// D3D11 Feature Level 10_0+ uses SV_IsFrontFace in HLSL to emulate gl_FrontFacing.
// D3D11 Feature Level 9_3 doesn't support SV_IsFrontFace, and has no equivalent, so can't support gl_FrontFacing.

View File

@@ -524,6 +524,7 @@ void Renderer9::generateDisplayExtensions(egl::DisplayExtensions *outExtensions)
outExtensions->postSubBuffer = true;
outExtensions->createContext = true;
outExtensions->deviceQuery = true;
outExtensions->createContextNoError = true;
outExtensions->image = true;
outExtensions->imageBase = true;

View File

@@ -577,6 +577,7 @@ void GenerateCaps(IDirect3D9 *d3d9,
extensions->unpackSubimage = true;
extensions->packSubimage = true;
extensions->vertexArrayObject = true;
extensions->noError = true;
// D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil
// state.

View File

@@ -55,18 +55,12 @@ ImageImpl *DisplayGL::createImage(EGLenum target,
return nullptr;
}
egl::Error DisplayGL::createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs, gl::Context **outContext)
gl::Context *DisplayGL::createContext(const egl::Config *config,
const gl::Context *shareContext,
const egl::AttributeMap &attribs)
{
ASSERT(mRenderer != nullptr);
EGLint clientVersion = attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1);
bool notifyResets = (attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_NO_RESET_NOTIFICATION_EXT) == EGL_LOSE_CONTEXT_ON_RESET_EXT);
bool robustAccess = (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE);
bool debug = (attribs.get(EGL_CONTEXT_OPENGL_DEBUG, EGL_FALSE) == EGL_TRUE);
*outContext = new gl::Context(config, clientVersion, shareContext, mRenderer, notifyResets,
robustAccess, debug);
return egl::Error(EGL_SUCCESS);
return new gl::Context(config, shareContext, mRenderer, attribs);
}
egl::Error DisplayGL::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context)

View File

@@ -30,8 +30,9 @@ class DisplayGL : public DisplayImpl
egl::ImageSibling *buffer,
const egl::AttributeMap &attribs) override;
egl::Error createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs,
gl::Context **outContext) override;
gl::Context *createContext(const egl::Config *config,
const gl::Context *shareContext,
const egl::AttributeMap &attribs) override;
egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) override;

View File

@@ -248,6 +248,7 @@ const FunctionsGL *DisplayCGL::getFunctionsGL() const
void DisplayCGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
{
outExtensions->createContext = true;
outExtensions->createContextNoError = true;
}
void DisplayCGL::generateCaps(egl::Caps *outCaps) const

View File

@@ -703,6 +703,7 @@ const FunctionsGL *DisplayGLX::getFunctionsGL() const
void DisplayGLX::generateExtensions(egl::DisplayExtensions *outExtensions) const
{
outExtensions->createContext = true;
outExtensions->createContextNoError = true;
}
void DisplayGLX::generateCaps(egl::Caps *outCaps) const

View File

@@ -611,6 +611,8 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
// ANGLE emulates vertex array objects in its GL layer
extensions->vertexArrayObject = true;
extensions->noError = true;
}
void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workarounds)

View File

@@ -467,6 +467,7 @@ const FunctionsGL *DisplayWGL::getFunctionsGL() const
void DisplayWGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
{
outExtensions->createContext = true;
outExtensions->createContextNoError = true;
}
void DisplayWGL::generateCaps(egl::Caps *outCaps) const

View File

@@ -248,6 +248,17 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context
}
break;
case EGL_CONTEXT_OPENGL_NO_ERROR_KHR:
if (!display->getExtensions().createContextNoError)
{
return Error(EGL_BAD_ATTRIBUTE, "Invalid Context attribute.");
}
if (value != EGL_TRUE && value != EGL_FALSE)
{
return Error(EGL_BAD_ATTRIBUTE, "Attribute must be EGL_TRUE or EGL_FALSE.");
}
break;
default:
return Error(EGL_BAD_ATTRIBUTE);
}

View File

@@ -42,7 +42,8 @@ class MockValidationContext : public ValidationContext
const TextureCapsMap &textureCaps,
const Extensions &extensions,
const ResourceManager *resourceManager,
const Limitations &limitations);
const Limitations &limitations,
bool skipValidation);
MOCK_METHOD1(recordError, void(const Error &));
};
@@ -53,14 +54,16 @@ MockValidationContext::MockValidationContext(GLint clientVersion,
const TextureCapsMap &textureCaps,
const Extensions &extensions,
const ResourceManager *resourceManager,
const Limitations &limitations)
const Limitations &limitations,
bool skipValidation)
: ValidationContext(clientVersion,
state,
caps,
textureCaps,
extensions,
resourceManager,
limitations)
limitations,
skipValidation)
{
}
@@ -115,8 +118,8 @@ TEST(ValidationESTest, DrawElementsWithMaxIndexGivesError)
state.setDrawFramebufferBinding(framebuffer);
state.setProgram(program);
MockValidationContext testContext(3, state, caps, textureCaps, extensions, nullptr,
limitations);
MockValidationContext testContext(3, state, caps, textureCaps, extensions, nullptr, limitations,
false);
// Set the expectation for the validation error here.
Error expectedError(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage);