mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 996266 - Support testing for errors at the GLContext level. - r=kamidphish
This commit is contained in:
parent
9451a4fa01
commit
323f57a297
@ -38,7 +38,6 @@ RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GLuint
|
||||
CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat,
|
||||
GLenum aType, const gfx::IntSize& aSize, bool linear)
|
||||
@ -47,10 +46,16 @@ CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat,
|
||||
aGL->fGenTextures(1, &tex);
|
||||
ScopedBindTexture autoTex(aGL, tex);
|
||||
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, linear ? LOCAL_GL_LINEAR : LOCAL_GL_NEAREST);
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, linear ? LOCAL_GL_LINEAR : LOCAL_GL_NEAREST);
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D,
|
||||
LOCAL_GL_TEXTURE_MIN_FILTER, linear ? LOCAL_GL_LINEAR
|
||||
: LOCAL_GL_NEAREST);
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D,
|
||||
LOCAL_GL_TEXTURE_MAG_FILTER, linear ? LOCAL_GL_LINEAR
|
||||
: LOCAL_GL_NEAREST);
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S,
|
||||
LOCAL_GL_CLAMP_TO_EDGE);
|
||||
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T,
|
||||
LOCAL_GL_CLAMP_TO_EDGE);
|
||||
|
||||
aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D,
|
||||
0,
|
||||
|
@ -277,7 +277,7 @@ GLContext::GLContext(const SurfaceCaps& caps,
|
||||
mRenderer(GLRenderer::Other),
|
||||
mHasRobustness(false),
|
||||
#ifdef DEBUG
|
||||
mGLError(LOCAL_GL_NO_ERROR),
|
||||
mIsInLocalErrorCheck(false),
|
||||
#endif
|
||||
mSharedContext(sharedContext),
|
||||
mCaps(caps),
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <ctype.h>
|
||||
#include <map>
|
||||
#include <bitset>
|
||||
#include <queue>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <string.h>
|
||||
@ -505,7 +506,6 @@ private:
|
||||
// -----------------------------------------------------------------------------
|
||||
// Robustness handling
|
||||
public:
|
||||
|
||||
bool HasRobustness() const {
|
||||
return mHasRobustness;
|
||||
}
|
||||
@ -516,17 +516,13 @@ public:
|
||||
*/
|
||||
virtual bool SupportsRobustness() const = 0;
|
||||
|
||||
|
||||
private:
|
||||
bool mHasRobustness;
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Error handling
|
||||
public:
|
||||
|
||||
static const char* GLErrorToString(GLenum aError)
|
||||
{
|
||||
static const char* GLErrorToString(GLenum aError) {
|
||||
switch (aError) {
|
||||
case LOCAL_GL_INVALID_ENUM:
|
||||
return "GL_INVALID_ENUM";
|
||||
@ -549,12 +545,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** \returns the first GL error, and guarantees that all GL error flags are cleared,
|
||||
* i.e. that a subsequent GetError call will return NO_ERROR
|
||||
*/
|
||||
GLenum GetAndClearError()
|
||||
{
|
||||
GLenum GetAndClearError() {
|
||||
// the first error is what we want to return
|
||||
GLenum error = fGetError();
|
||||
|
||||
@ -566,30 +560,99 @@ public:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/*** In GL debug mode, we completely override glGetError ***/
|
||||
|
||||
GLenum fGetError()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// debug mode ends up eating the error in AFTER_GL_CALL
|
||||
if (DebugMode()) {
|
||||
GLenum err = mGLError;
|
||||
mGLError = LOCAL_GL_NO_ERROR;
|
||||
return err;
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
private:
|
||||
GLenum raw_fGetError() {
|
||||
return mSymbols.fGetError();
|
||||
}
|
||||
|
||||
std::queue<GLenum> mGLErrorQueue;
|
||||
|
||||
public:
|
||||
GLenum fGetError() {
|
||||
if (!mGLErrorQueue.empty()) {
|
||||
GLenum err = mGLErrorQueue.front();
|
||||
mGLErrorQueue.pop();
|
||||
return err;
|
||||
}
|
||||
|
||||
return GetUnpushedError();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
private:
|
||||
GLenum GetUnpushedError() {
|
||||
return raw_fGetError();
|
||||
}
|
||||
|
||||
GLenum mGLError;
|
||||
#endif // DEBUG
|
||||
void ClearUnpushedErrors() {
|
||||
while (GetUnpushedError()) {
|
||||
// Discard errors.
|
||||
}
|
||||
}
|
||||
|
||||
GLenum GetAndClearUnpushedErrors() {
|
||||
GLenum err = GetUnpushedError();
|
||||
if (err) {
|
||||
ClearUnpushedErrors();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void PushError(GLenum err) {
|
||||
mGLErrorQueue.push(err);
|
||||
}
|
||||
|
||||
void GetAndPushAllErrors() {
|
||||
while (true) {
|
||||
GLenum err = GetUnpushedError();
|
||||
if (!err)
|
||||
break;
|
||||
|
||||
PushError(err);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////
|
||||
// Use this safer option.
|
||||
private:
|
||||
#ifdef DEBUG
|
||||
bool mIsInLocalErrorCheck;
|
||||
#endif
|
||||
|
||||
public:
|
||||
class ScopedLocalErrorCheck {
|
||||
GLContext* const mGL;
|
||||
bool mHasBeenChecked;
|
||||
|
||||
public:
|
||||
ScopedLocalErrorCheck(GLContext* gl)
|
||||
: mGL(gl)
|
||||
, mHasBeenChecked(false)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(!mGL->mIsInLocalErrorCheck);
|
||||
mGL->mIsInLocalErrorCheck = true;
|
||||
#endif
|
||||
mGL->GetAndPushAllErrors();
|
||||
}
|
||||
|
||||
GLenum GetLocalError() {
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(mGL->mIsInLocalErrorCheck);
|
||||
mGL->mIsInLocalErrorCheck = false;
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(!mHasBeenChecked);
|
||||
mHasBeenChecked = true;
|
||||
|
||||
return mGL->GetAndClearUnpushedErrors();
|
||||
}
|
||||
|
||||
~ScopedLocalErrorCheck() {
|
||||
MOZ_ASSERT(mHasBeenChecked);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
static void GLAPIENTRY StaticDebugCallback(GLenum source,
|
||||
GLenum type,
|
||||
GLuint id,
|
||||
@ -624,8 +687,7 @@ private:
|
||||
# endif
|
||||
#endif
|
||||
|
||||
void BeforeGLCall(const char* glFunction)
|
||||
{
|
||||
void BeforeGLCall(const char* glFunction) {
|
||||
MOZ_ASSERT(IsCurrent());
|
||||
if (DebugMode()) {
|
||||
GLContext *currentGLContext = nullptr;
|
||||
@ -643,21 +705,23 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void AfterGLCall(const char* glFunction)
|
||||
{
|
||||
void AfterGLCall(const char* glFunction) {
|
||||
if (DebugMode()) {
|
||||
// calling fFinish() immediately after every GL call makes sure that if this GL command crashes,
|
||||
// the stack trace will actually point to it. Otherwise, OpenGL being an asynchronous API, stack traces
|
||||
// tend to be meaningless
|
||||
mSymbols.fFinish();
|
||||
mGLError = mSymbols.fGetError();
|
||||
GLenum err = GetUnpushedError();
|
||||
PushError(err);
|
||||
|
||||
if (DebugMode() & DebugTrace)
|
||||
printf_stderr("[gl:%p] < %s [0x%04x]\n", this, glFunction, mGLError);
|
||||
if (mGLError != LOCAL_GL_NO_ERROR) {
|
||||
printf_stderr("[gl:%p] < %s [0x%04x]\n", this, glFunction, err);
|
||||
|
||||
if (err != LOCAL_GL_NO_ERROR) {
|
||||
printf_stderr("GL ERROR: %s generated GL error %s(0x%04x)\n",
|
||||
glFunction,
|
||||
GLErrorToString(mGLError),
|
||||
mGLError);
|
||||
GLErrorToString(err),
|
||||
err);
|
||||
if (DebugMode() & DebugAbortOnError)
|
||||
NS_ABORT();
|
||||
}
|
||||
|
@ -568,6 +568,8 @@ DrawBuffer::Create(GLContext* const gl,
|
||||
pStencilRB = nullptr;
|
||||
}
|
||||
|
||||
GLContext::ScopedLocalErrorCheck localError(gl);
|
||||
|
||||
CreateRenderbuffersForOffscreen(gl, formats, size, caps.antialias,
|
||||
pColorMSRB, pDepthRB, pStencilRB);
|
||||
|
||||
@ -578,7 +580,8 @@ DrawBuffer::Create(GLContext* const gl,
|
||||
UniquePtr<DrawBuffer> ret( new DrawBuffer(gl, size, fb, colorMSRB,
|
||||
depthRB, stencilRB) );
|
||||
|
||||
if (!gl->IsFramebufferComplete(fb))
|
||||
GLenum err = localError.GetLocalError();
|
||||
if (err || !gl->IsFramebufferComplete(fb))
|
||||
return false;
|
||||
|
||||
*out_buffer = Move(ret);
|
||||
@ -624,6 +627,8 @@ ReadBuffer::Create(GLContext* gl,
|
||||
GLuint* pDepthRB = caps.depth ? &depthRB : nullptr;
|
||||
GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr;
|
||||
|
||||
GLContext::ScopedLocalErrorCheck localError(gl);
|
||||
|
||||
CreateRenderbuffersForOffscreen(gl, formats, surf->mSize, caps.antialias,
|
||||
nullptr, pDepthRB, pStencilRB);
|
||||
|
||||
@ -651,7 +656,9 @@ ReadBuffer::Create(GLContext* gl,
|
||||
|
||||
UniquePtr<ReadBuffer> ret( new ReadBuffer(gl, fb, depthRB,
|
||||
stencilRB, surf) );
|
||||
if (!gl->IsFramebufferComplete(fb)) {
|
||||
|
||||
GLenum err = localError.GetLocalError();
|
||||
if (err || !gl->IsFramebufferComplete(fb)) {
|
||||
ret = nullptr;
|
||||
}
|
||||
|
||||
|
@ -144,20 +144,28 @@ ChooseConfig(GLContext* gl,
|
||||
return config;
|
||||
}
|
||||
|
||||
// Returns EGL_NO_SURFACE on error.
|
||||
// Returns `EGL_NO_SURFACE` (`0`) on error.
|
||||
static EGLSurface
|
||||
CreatePBufferSurface(GLLibraryEGL* egl,
|
||||
EGLDisplay display,
|
||||
EGLConfig config,
|
||||
const gfx::IntSize& size)
|
||||
{
|
||||
auto width = size.width;
|
||||
auto height = size.height;
|
||||
|
||||
EGLint attribs[] = {
|
||||
LOCAL_EGL_WIDTH, size.width,
|
||||
LOCAL_EGL_HEIGHT, size.height,
|
||||
LOCAL_EGL_WIDTH, width,
|
||||
LOCAL_EGL_HEIGHT, height,
|
||||
LOCAL_EGL_NONE
|
||||
};
|
||||
|
||||
DebugOnly<EGLint> preCallErr = egl->fGetError();
|
||||
MOZ_ASSERT(preCallErr == LOCAL_EGL_SUCCESS);
|
||||
EGLSurface surface = egl->fCreatePbufferSurface(display, config, attribs);
|
||||
EGLint err = egl->fGetError();
|
||||
if (err != LOCAL_EGL_SUCCESS)
|
||||
return 0;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
@ -24,10 +24,17 @@ SharedSurface_Basic::Create(GLContext* gl,
|
||||
bool hasAlpha)
|
||||
{
|
||||
gl->MakeCurrent();
|
||||
|
||||
GLContext::ScopedLocalErrorCheck localError(gl);
|
||||
GLuint tex = CreateTexture(gl, formats.color_texInternalFormat,
|
||||
formats.color_texFormat,
|
||||
formats.color_texType,
|
||||
size);
|
||||
GLenum err = localError.GetLocalError();
|
||||
if (err) {
|
||||
gl->fDeleteTextures(1, &tex);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SurfaceFormat format = SurfaceFormat::B8G8R8X8;
|
||||
switch (formats.color_texInternalFormat) {
|
||||
@ -74,11 +81,8 @@ SharedSurface_Basic::SharedSurface_Basic(GLContext* gl,
|
||||
mTex,
|
||||
0);
|
||||
|
||||
GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
mGL->fDeleteFramebuffers(1, &mFB);
|
||||
mFB = 0;
|
||||
}
|
||||
DebugOnly<GLenum> status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||
MOZ_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
|
||||
|
||||
int32_t stride = gfx::GetAlignedStride<4>(size.width * BytesPerPixel(format));
|
||||
mData = gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride);
|
||||
@ -133,14 +137,24 @@ SharedSurface_GLTexture::Create(GLContext* prodGL,
|
||||
|
||||
bool ownsTex = false;
|
||||
|
||||
UniquePtr<SharedSurface_GLTexture> ret;
|
||||
|
||||
if (!tex) {
|
||||
GLContext::ScopedLocalErrorCheck localError(prodGL);
|
||||
|
||||
tex = CreateTextureForOffscreen(prodGL, formats, size);
|
||||
|
||||
GLenum err = localError.GetLocalError();
|
||||
if (err) {
|
||||
prodGL->fDeleteTextures(1, &tex);
|
||||
return Move(ret);
|
||||
}
|
||||
|
||||
ownsTex = true;
|
||||
}
|
||||
|
||||
typedef SharedSurface_GLTexture ptrT;
|
||||
UniquePtr<ptrT> ret( new ptrT(prodGL, consGL, size, hasAlpha, tex,
|
||||
ownsTex) );
|
||||
ret.reset( new SharedSurface_GLTexture(prodGL, consGL, size,
|
||||
hasAlpha, tex, ownsTex) );
|
||||
return Move(ret);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user