summaryrefslogtreecommitdiffstats
path: root/gfx/gl/ScopedGLHelpers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/gl/ScopedGLHelpers.cpp')
-rw-r--r--gfx/gl/ScopedGLHelpers.cpp540
1 files changed, 540 insertions, 0 deletions
diff --git a/gfx/gl/ScopedGLHelpers.cpp b/gfx/gl/ScopedGLHelpers.cpp
new file mode 100644
index 000000000..fade35788
--- /dev/null
+++ b/gfx/gl/ScopedGLHelpers.cpp
@@ -0,0 +1,540 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/UniquePtr.h"
+
+#include "GLContext.h"
+#include "ScopedGLHelpers.h"
+
+namespace mozilla {
+namespace gl {
+
+#ifdef DEBUG
+bool
+IsContextCurrent(GLContext* gl)
+{
+ return gl->IsCurrent();
+}
+#endif
+
+/* ScopedGLState - Wraps glEnable/glDisable. **********************************/
+
+// Use |newState = true| to enable, |false| to disable.
+ScopedGLState::ScopedGLState(GLContext* aGL, GLenum aCapability, bool aNewState)
+ : ScopedGLWrapper<ScopedGLState>(aGL)
+ , mCapability(aCapability)
+{
+ mOldState = mGL->fIsEnabled(mCapability);
+
+ // Early out if we're already in the right state.
+ if (aNewState == mOldState)
+ return;
+
+ if (aNewState) {
+ mGL->fEnable(mCapability);
+ } else {
+ mGL->fDisable(mCapability);
+ }
+}
+
+ScopedGLState::ScopedGLState(GLContext* aGL, GLenum aCapability)
+ : ScopedGLWrapper<ScopedGLState>(aGL)
+ , mCapability(aCapability)
+{
+ mOldState = mGL->fIsEnabled(mCapability);
+}
+
+void
+ScopedGLState::UnwrapImpl()
+{
+ if (mOldState) {
+ mGL->fEnable(mCapability);
+ } else {
+ mGL->fDisable(mCapability);
+ }
+}
+
+
+/* ScopedBindFramebuffer - Saves and restores with GetUserBoundFB and BindUserFB. */
+
+void
+ScopedBindFramebuffer::Init()
+{
+ if (mGL->IsSupported(GLFeature::split_framebuffer)) {
+ mOldReadFB = mGL->GetReadFB();
+ mOldDrawFB = mGL->GetDrawFB();
+ } else {
+ mOldReadFB = mOldDrawFB = mGL->GetFB();
+ }
+}
+
+ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL)
+ : ScopedGLWrapper<ScopedBindFramebuffer>(aGL)
+{
+ Init();
+}
+
+ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL, GLuint aNewFB)
+ : ScopedGLWrapper<ScopedBindFramebuffer>(aGL)
+{
+ Init();
+ mGL->BindFB(aNewFB);
+}
+
+void
+ScopedBindFramebuffer::UnwrapImpl()
+{
+ if (mOldReadFB == mOldDrawFB) {
+ mGL->BindFB(mOldDrawFB);
+ } else {
+ mGL->BindDrawFB(mOldDrawFB);
+ mGL->BindReadFB(mOldReadFB);
+ }
+}
+
+
+/* ScopedBindTextureUnit ******************************************************/
+
+ScopedBindTextureUnit::ScopedBindTextureUnit(GLContext* aGL, GLenum aTexUnit)
+ : ScopedGLWrapper<ScopedBindTextureUnit>(aGL)
+{
+ MOZ_ASSERT(aTexUnit >= LOCAL_GL_TEXTURE0);
+ mGL->GetUIntegerv(LOCAL_GL_ACTIVE_TEXTURE, &mOldTexUnit);
+ mGL->fActiveTexture(aTexUnit);
+}
+
+void
+ScopedBindTextureUnit::UnwrapImpl() {
+ mGL->fActiveTexture(mOldTexUnit);
+}
+
+
+/* ScopedTexture **************************************************************/
+
+ScopedTexture::ScopedTexture(GLContext* aGL)
+ : ScopedGLWrapper<ScopedTexture>(aGL)
+{
+ mGL->fGenTextures(1, &mTexture);
+}
+
+void
+ScopedTexture::UnwrapImpl()
+{
+ mGL->fDeleteTextures(1, &mTexture);
+}
+
+/* ScopedFramebuffer **************************************************************/
+
+ScopedFramebuffer::ScopedFramebuffer(GLContext* aGL)
+ : ScopedGLWrapper<ScopedFramebuffer>(aGL)
+{
+ mGL->fGenFramebuffers(1, &mFB);
+}
+
+void
+ScopedFramebuffer::UnwrapImpl()
+{
+ mGL->fDeleteFramebuffers(1, &mFB);
+}
+
+
+/* ScopedRenderbuffer **************************************************************/
+
+ScopedRenderbuffer::ScopedRenderbuffer(GLContext* aGL)
+ : ScopedGLWrapper<ScopedRenderbuffer>(aGL)
+{
+ mGL->fGenRenderbuffers(1, &mRB);
+}
+
+void
+ScopedRenderbuffer::UnwrapImpl()
+{
+ mGL->fDeleteRenderbuffers(1, &mRB);
+}
+
+/* ScopedBindTexture **********************************************************/
+
+static GLuint
+GetBoundTexture(GLContext* gl, GLenum texTarget)
+{
+ GLenum bindingTarget;
+ switch (texTarget) {
+ case LOCAL_GL_TEXTURE_2D:
+ bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D;
+ break;
+
+ case LOCAL_GL_TEXTURE_CUBE_MAP:
+ bindingTarget = LOCAL_GL_TEXTURE_BINDING_CUBE_MAP;
+ break;
+
+ case LOCAL_GL_TEXTURE_3D:
+ bindingTarget = LOCAL_GL_TEXTURE_BINDING_3D;
+ break;
+
+ case LOCAL_GL_TEXTURE_2D_ARRAY:
+ bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D_ARRAY;
+ break;
+
+ case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
+ bindingTarget = LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB;
+ break;
+
+ case LOCAL_GL_TEXTURE_EXTERNAL:
+ bindingTarget = LOCAL_GL_TEXTURE_BINDING_EXTERNAL;
+ break;
+
+ default:
+ MOZ_CRASH("bad texTarget");
+ }
+
+ GLuint ret = 0;
+ gl->GetUIntegerv(bindingTarget, &ret);
+ return ret;
+}
+
+ScopedBindTexture::ScopedBindTexture(GLContext* aGL, GLuint aNewTex, GLenum aTarget)
+ : ScopedGLWrapper<ScopedBindTexture>(aGL)
+ , mTarget(aTarget)
+ , mOldTex(GetBoundTexture(aGL, aTarget))
+{
+ mGL->fBindTexture(mTarget, aNewTex);
+}
+
+void
+ScopedBindTexture::UnwrapImpl()
+{
+ mGL->fBindTexture(mTarget, mOldTex);
+}
+
+
+/* ScopedBindRenderbuffer *****************************************************/
+
+void
+ScopedBindRenderbuffer::Init()
+{
+ mOldRB = 0;
+ mGL->GetUIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &mOldRB);
+}
+
+ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext* aGL)
+ : ScopedGLWrapper<ScopedBindRenderbuffer>(aGL)
+{
+ Init();
+}
+
+ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext* aGL, GLuint aNewRB)
+ : ScopedGLWrapper<ScopedBindRenderbuffer>(aGL)
+{
+ Init();
+ mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, aNewRB);
+}
+
+void
+ScopedBindRenderbuffer::UnwrapImpl()
+{
+ mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOldRB);
+}
+
+
+/* ScopedFramebufferForTexture ************************************************/
+ScopedFramebufferForTexture::ScopedFramebufferForTexture(GLContext* aGL,
+ GLuint aTexture,
+ GLenum aTarget)
+ : ScopedGLWrapper<ScopedFramebufferForTexture>(aGL)
+ , mComplete(false)
+ , mFB(0)
+{
+ mGL->fGenFramebuffers(1, &mFB);
+ ScopedBindFramebuffer autoFB(aGL, mFB);
+ mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
+ LOCAL_GL_COLOR_ATTACHMENT0,
+ aTarget,
+ aTexture,
+ 0);
+
+ GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
+ if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+ mComplete = true;
+ } else {
+ mGL->fDeleteFramebuffers(1, &mFB);
+ mFB = 0;
+ }
+}
+
+void ScopedFramebufferForTexture::UnwrapImpl()
+{
+ if (!mFB)
+ return;
+
+ mGL->fDeleteFramebuffers(1, &mFB);
+ mFB = 0;
+}
+
+
+/* ScopedFramebufferForRenderbuffer *******************************************/
+
+
+ScopedFramebufferForRenderbuffer::ScopedFramebufferForRenderbuffer(GLContext* aGL,
+ GLuint aRB)
+ : ScopedGLWrapper<ScopedFramebufferForRenderbuffer>(aGL)
+ , mComplete(false)
+ , mFB(0)
+{
+ mGL->fGenFramebuffers(1, &mFB);
+ ScopedBindFramebuffer autoFB(aGL, mFB);
+ mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
+ LOCAL_GL_COLOR_ATTACHMENT0,
+ LOCAL_GL_RENDERBUFFER,
+ aRB);
+
+ GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
+ if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+ mComplete = true;
+ } else {
+ mGL->fDeleteFramebuffers(1, &mFB);
+ mFB = 0;
+ }
+}
+
+void
+ScopedFramebufferForRenderbuffer::UnwrapImpl()
+{
+ if (!mFB)
+ return;
+
+ mGL->fDeleteFramebuffers(1, &mFB);
+ mFB = 0;
+}
+
+/* ScopedViewportRect *********************************************************/
+
+ScopedViewportRect::ScopedViewportRect(GLContext* aGL,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height)
+ : ScopedGLWrapper<ScopedViewportRect>(aGL)
+{
+ mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, mSavedViewportRect);
+ mGL->fViewport(x, y, width, height);
+}
+
+void ScopedViewportRect::UnwrapImpl()
+{
+ mGL->fViewport(mSavedViewportRect[0],
+ mSavedViewportRect[1],
+ mSavedViewportRect[2],
+ mSavedViewportRect[3]);
+}
+
+/* ScopedScissorRect **********************************************************/
+
+ScopedScissorRect::ScopedScissorRect(GLContext* aGL,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height)
+ : ScopedGLWrapper<ScopedScissorRect>(aGL)
+{
+ mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect);
+ mGL->fScissor(x, y, width, height);
+}
+
+ScopedScissorRect::ScopedScissorRect(GLContext* aGL)
+ : ScopedGLWrapper<ScopedScissorRect>(aGL)
+{
+ mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect);
+}
+
+void ScopedScissorRect::UnwrapImpl()
+{
+ mGL->fScissor(mSavedScissorRect[0],
+ mSavedScissorRect[1],
+ mSavedScissorRect[2],
+ mSavedScissorRect[3]);
+}
+
+/* ScopedVertexAttribPointer **************************************************/
+
+ScopedVertexAttribPointer::ScopedVertexAttribPointer(GLContext* aGL,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ realGLboolean normalized,
+ GLsizei stride,
+ GLuint buffer,
+ const GLvoid* pointer)
+ : ScopedGLWrapper<ScopedVertexAttribPointer>(aGL)
+{
+ WrapImpl(index);
+ mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer);
+ mGL->fVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ mGL->fEnableVertexAttribArray(index);
+}
+
+ScopedVertexAttribPointer::ScopedVertexAttribPointer(GLContext* aGL,
+ GLuint index)
+ : ScopedGLWrapper<ScopedVertexAttribPointer>(aGL)
+{
+ WrapImpl(index);
+}
+
+void
+ScopedVertexAttribPointer::WrapImpl(GLuint index)
+{
+ mAttribIndex = index;
+
+ /*
+ * mGL->fGetVertexAttribiv takes:
+ * VERTEX_ATTRIB_ARRAY_ENABLED
+ * VERTEX_ATTRIB_ARRAY_SIZE,
+ * VERTEX_ATTRIB_ARRAY_STRIDE,
+ * VERTEX_ATTRIB_ARRAY_TYPE,
+ * VERTEX_ATTRIB_ARRAY_NORMALIZED,
+ * VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
+ * CURRENT_VERTEX_ATTRIB
+ *
+ * CURRENT_VERTEX_ATTRIB is vertex shader state. \o/
+ * Others appear to be vertex array state,
+ * or alternatively in the internal vertex array state
+ * for a buffer object.
+ */
+
+ mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED, &mAttribEnabled);
+ mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE, &mAttribSize);
+ mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE, &mAttribStride);
+ mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE, &mAttribType);
+ mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &mAttribNormalized);
+ mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &mAttribBufferBinding);
+ mGL->fGetVertexAttribPointerv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER, &mAttribPointer);
+
+ // Note that uniform values are program state, so we don't need to rebind those.
+
+ mGL->GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING, &mBoundBuffer);
+}
+
+void
+ScopedVertexAttribPointer::UnwrapImpl()
+{
+ mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mAttribBufferBinding);
+ mGL->fVertexAttribPointer(mAttribIndex, mAttribSize, mAttribType, mAttribNormalized, mAttribStride, mAttribPointer);
+ if (mAttribEnabled)
+ mGL->fEnableVertexAttribArray(mAttribIndex);
+ else
+ mGL->fDisableVertexAttribArray(mAttribIndex);
+ mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundBuffer);
+}
+
+ScopedGLDrawState::ScopedGLDrawState(GLContext* aGL)
+ : blend (aGL, LOCAL_GL_BLEND, false)
+ , cullFace (aGL, LOCAL_GL_CULL_FACE, false)
+ , depthTest (aGL, LOCAL_GL_DEPTH_TEST, false)
+ , dither (aGL, LOCAL_GL_DITHER, false)
+ , polyOffsFill(aGL, LOCAL_GL_POLYGON_OFFSET_FILL, false)
+ , sampleAToC (aGL, LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, false)
+ , sampleCover (aGL, LOCAL_GL_SAMPLE_COVERAGE, false)
+ , scissor (aGL, LOCAL_GL_SCISSOR_TEST, false)
+ , stencil (aGL, LOCAL_GL_STENCIL_TEST, false)
+ , mGL(aGL)
+{
+ mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, &boundProgram);
+ mGL->GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING, &boundBuffer);
+ mGL->GetUIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &maxAttrib);
+ attrib_enabled = MakeUnique<GLint[]>(maxAttrib);
+
+ for (GLuint i = 0; i < maxAttrib; i++) {
+ mGL->fGetVertexAttribiv(i, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED, &attrib_enabled[i]);
+ mGL->fDisableVertexAttribArray(i);
+ }
+ // Only Attrib0's client side state affected
+ mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib0_size);
+ mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib0_stride);
+ mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib0_type);
+ mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &attrib0_normalized);
+ mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &attrib0_bufferBinding);
+ mGL->fGetVertexAttribPointerv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib0_pointer);
+ mGL->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorMask);
+ mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
+ mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, scissorBox);
+}
+
+ScopedGLDrawState::~ScopedGLDrawState()
+{
+ MOZ_ASSERT(mGL->IsCurrent());
+
+ mGL->fScissor(scissorBox[0], scissorBox[1],
+ scissorBox[2], scissorBox[3]);
+
+ mGL->fViewport(viewport[0], viewport[1],
+ viewport[2], viewport[3]);
+
+ mGL->fColorMask(colorMask[0],
+ colorMask[1],
+ colorMask[2],
+ colorMask[3]);
+
+ for (unsigned int i = 0; i < maxAttrib; i++) {
+ if (attrib_enabled[i])
+ mGL->fEnableVertexAttribArray(i);
+ else
+ mGL->fDisableVertexAttribArray(i);
+ }
+
+
+ mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0_bufferBinding);
+ mGL->fVertexAttribPointer(0,
+ attrib0_size,
+ attrib0_type,
+ attrib0_normalized,
+ attrib0_stride,
+ attrib0_pointer);
+
+ mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, boundBuffer);
+
+ mGL->fUseProgram(boundProgram);
+}
+
+////////////////////////////////////////////////////////////////////////
+// ScopedPackState
+
+static bool
+HasPBOState(const GLContext* gl)
+{
+ return (!gl->IsGLES() || gl->Version() >= 300);
+}
+
+ScopedPackState::ScopedPackState(GLContext* gl)
+ : ScopedGLWrapper<ScopedPackState>(gl)
+{
+ mGL->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &mAlignment);
+
+ if (mAlignment != 4) mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
+
+ if (!HasPBOState(mGL))
+ return;
+
+ mGL->fGetIntegerv(LOCAL_GL_PIXEL_PACK_BUFFER_BINDING, (GLint*)&mPixelBuffer);
+ mGL->fGetIntegerv(LOCAL_GL_PACK_ROW_LENGTH, &mRowLength);
+ mGL->fGetIntegerv(LOCAL_GL_PACK_SKIP_PIXELS, &mSkipPixels);
+ mGL->fGetIntegerv(LOCAL_GL_PACK_SKIP_ROWS, &mSkipRows);
+
+ if (mPixelBuffer != 0) mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, 0);
+ if (mRowLength != 0) mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, 0);
+ if (mSkipPixels != 0) mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, 0);
+ if (mSkipRows != 0) mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, 0);
+}
+
+void
+ScopedPackState::UnwrapImpl()
+{
+ mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mAlignment);
+
+ if (!HasPBOState(mGL))
+ return;
+
+ mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, mPixelBuffer);
+ mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mRowLength);
+ mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mSkipPixels);
+ mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mSkipRows);
+}
+
+} /* namespace gl */
+} /* namespace mozilla */