1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/UniquePtr.h"
9 #include "ScopedGLHelpers.h"
14 /* ScopedGLState - Wraps glEnable/glDisable. **********************************/
16 // Use |newState = true| to enable, |false| to disable.
17 ScopedGLState::ScopedGLState(GLContext
* aGL
, GLenum aCapability
, bool aNewState
)
18 : mGL(aGL
), mCapability(aCapability
) {
19 mOldState
= mGL
->fIsEnabled(mCapability
);
21 // Early out if we're already in the right state.
22 if (aNewState
== mOldState
) return;
25 mGL
->fEnable(mCapability
);
27 mGL
->fDisable(mCapability
);
31 ScopedGLState::ScopedGLState(GLContext
* aGL
, GLenum aCapability
)
32 : mGL(aGL
), mCapability(aCapability
) {
33 mOldState
= mGL
->fIsEnabled(mCapability
);
36 ScopedGLState::~ScopedGLState() {
38 mGL
->fEnable(mCapability
);
40 mGL
->fDisable(mCapability
);
44 /* ScopedBindFramebuffer - Saves and restores with GetUserBoundFB and
47 void ScopedBindFramebuffer::Init() {
48 if (mGL
->IsSupported(GLFeature::split_framebuffer
)) {
49 mOldReadFB
= mGL
->GetReadFB();
50 mOldDrawFB
= mGL
->GetDrawFB();
52 mOldReadFB
= mOldDrawFB
= mGL
->GetFB();
56 ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext
* aGL
) : mGL(aGL
) {
60 ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext
* aGL
, GLuint aNewFB
)
66 ScopedBindFramebuffer::~ScopedBindFramebuffer() {
67 if (mOldReadFB
== mOldDrawFB
) {
68 mGL
->BindFB(mOldDrawFB
);
70 mGL
->BindDrawFB(mOldDrawFB
);
71 mGL
->BindReadFB(mOldReadFB
);
75 /* ScopedBindTextureUnit ******************************************************/
77 ScopedBindTextureUnit::ScopedBindTextureUnit(GLContext
* aGL
, GLenum aTexUnit
)
78 : mGL(aGL
), mOldTexUnit(0) {
79 MOZ_ASSERT(aTexUnit
>= LOCAL_GL_TEXTURE0
);
80 mGL
->GetUIntegerv(LOCAL_GL_ACTIVE_TEXTURE
, &mOldTexUnit
);
81 mGL
->fActiveTexture(aTexUnit
);
84 ScopedBindTextureUnit::~ScopedBindTextureUnit() {
85 mGL
->fActiveTexture(mOldTexUnit
);
88 /* ScopedTexture **************************************************************/
90 ScopedTexture::ScopedTexture(GLContext
* aGL
) : mGL(aGL
), mTexture(0) {
91 mGL
->fGenTextures(1, &mTexture
);
94 ScopedTexture::~ScopedTexture() { mGL
->fDeleteTextures(1, &mTexture
); }
97 * **************************************************************/
99 ScopedFramebuffer::ScopedFramebuffer(GLContext
* aGL
) : mGL(aGL
), mFB(0) {
100 mGL
->fGenFramebuffers(1, &mFB
);
103 ScopedFramebuffer::~ScopedFramebuffer() { mGL
->fDeleteFramebuffers(1, &mFB
); }
105 /* ScopedRenderbuffer
106 * **************************************************************/
108 ScopedRenderbuffer::ScopedRenderbuffer(GLContext
* aGL
) : mGL(aGL
), mRB(0) {
109 mGL
->fGenRenderbuffers(1, &mRB
);
112 ScopedRenderbuffer::~ScopedRenderbuffer() {
113 mGL
->fDeleteRenderbuffers(1, &mRB
);
116 /* ScopedBindTexture **********************************************************/
118 static GLuint
GetBoundTexture(GLContext
* gl
, GLenum texTarget
) {
119 GLenum bindingTarget
;
121 case LOCAL_GL_TEXTURE_2D
:
122 bindingTarget
= LOCAL_GL_TEXTURE_BINDING_2D
;
125 case LOCAL_GL_TEXTURE_CUBE_MAP
:
126 bindingTarget
= LOCAL_GL_TEXTURE_BINDING_CUBE_MAP
;
129 case LOCAL_GL_TEXTURE_3D
:
130 bindingTarget
= LOCAL_GL_TEXTURE_BINDING_3D
;
133 case LOCAL_GL_TEXTURE_2D_ARRAY
:
134 bindingTarget
= LOCAL_GL_TEXTURE_BINDING_2D_ARRAY
;
137 case LOCAL_GL_TEXTURE_RECTANGLE_ARB
:
138 bindingTarget
= LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB
;
141 case LOCAL_GL_TEXTURE_EXTERNAL
:
142 bindingTarget
= LOCAL_GL_TEXTURE_BINDING_EXTERNAL
;
146 MOZ_CRASH("bad texTarget");
150 gl
->GetUIntegerv(bindingTarget
, &ret
);
154 ScopedBindTexture::ScopedBindTexture(GLContext
* aGL
, GLuint aNewTex
,
156 : mGL(aGL
), mTarget(aTarget
), mOldTex(GetBoundTexture(aGL
, aTarget
)) {
157 mGL
->fBindTexture(mTarget
, aNewTex
);
160 ScopedBindTexture::~ScopedBindTexture() { mGL
->fBindTexture(mTarget
, mOldTex
); }
162 /* ScopedBindRenderbuffer *****************************************************/
164 void ScopedBindRenderbuffer::Init() {
166 mGL
->GetUIntegerv(LOCAL_GL_RENDERBUFFER_BINDING
, &mOldRB
);
169 ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext
* aGL
) : mGL(aGL
) {
173 ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext
* aGL
, GLuint aNewRB
)
176 mGL
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, aNewRB
);
179 ScopedBindRenderbuffer::~ScopedBindRenderbuffer() {
180 mGL
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, mOldRB
);
183 /* ScopedFramebufferForTexture ************************************************/
184 ScopedFramebufferForTexture::ScopedFramebufferForTexture(GLContext
* aGL
,
187 : mGL(aGL
), mComplete(false), mFB(0) {
188 mGL
->fGenFramebuffers(1, &mFB
);
189 ScopedBindFramebuffer
autoFB(aGL
, mFB
);
190 mGL
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_COLOR_ATTACHMENT0
,
191 aTarget
, aTexture
, 0);
193 GLenum status
= mGL
->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER
);
194 if (status
== LOCAL_GL_FRAMEBUFFER_COMPLETE
) {
197 mGL
->fDeleteFramebuffers(1, &mFB
);
202 ScopedFramebufferForTexture::~ScopedFramebufferForTexture() {
205 mGL
->fDeleteFramebuffers(1, &mFB
);
209 /* ScopedFramebufferForRenderbuffer *******************************************/
211 ScopedFramebufferForRenderbuffer::ScopedFramebufferForRenderbuffer(
212 GLContext
* aGL
, GLuint aRB
)
213 : mGL(aGL
), mComplete(false), mFB(0) {
214 mGL
->fGenFramebuffers(1, &mFB
);
215 ScopedBindFramebuffer
autoFB(aGL
, mFB
);
216 mGL
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
,
217 LOCAL_GL_COLOR_ATTACHMENT0
,
218 LOCAL_GL_RENDERBUFFER
, aRB
);
220 GLenum status
= mGL
->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER
);
221 if (status
== LOCAL_GL_FRAMEBUFFER_COMPLETE
) {
224 mGL
->fDeleteFramebuffers(1, &mFB
);
229 ScopedFramebufferForRenderbuffer::~ScopedFramebufferForRenderbuffer() {
232 mGL
->fDeleteFramebuffers(1, &mFB
);
236 /* ScopedViewportRect *********************************************************/
238 ScopedViewportRect::ScopedViewportRect(GLContext
* aGL
, GLint x
, GLint y
,
239 GLsizei width
, GLsizei height
)
241 mGL
->fGetIntegerv(LOCAL_GL_VIEWPORT
, mSavedViewportRect
);
242 mGL
->fViewport(x
, y
, width
, height
);
245 ScopedViewportRect::~ScopedViewportRect() {
246 mGL
->fViewport(mSavedViewportRect
[0], mSavedViewportRect
[1],
247 mSavedViewportRect
[2], mSavedViewportRect
[3]);
250 /* ScopedScissorRect **********************************************************/
252 ScopedScissorRect::ScopedScissorRect(GLContext
* aGL
, GLint x
, GLint y
,
253 GLsizei width
, GLsizei height
)
255 mGL
->fGetIntegerv(LOCAL_GL_SCISSOR_BOX
, mSavedScissorRect
);
256 mGL
->fScissor(x
, y
, width
, height
);
259 ScopedScissorRect::ScopedScissorRect(GLContext
* aGL
) : mGL(aGL
) {
260 mGL
->fGetIntegerv(LOCAL_GL_SCISSOR_BOX
, mSavedScissorRect
);
263 ScopedScissorRect::~ScopedScissorRect() {
264 mGL
->fScissor(mSavedScissorRect
[0], mSavedScissorRect
[1],
265 mSavedScissorRect
[2], mSavedScissorRect
[3]);
268 /* ScopedVertexAttribPointer **************************************************/
270 ScopedVertexAttribPointer::ScopedVertexAttribPointer(
271 GLContext
* aGL
, GLuint index
, GLint size
, GLenum type
,
272 realGLboolean normalized
, GLsizei stride
, GLuint buffer
,
273 const GLvoid
* pointer
)
279 mAttribNormalized(0),
280 mAttribBufferBinding(0),
281 mAttribPointer(nullptr),
284 mGL
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, buffer
);
285 mGL
->fVertexAttribPointer(index
, size
, type
, normalized
, stride
, pointer
);
286 mGL
->fEnableVertexAttribArray(index
);
289 ScopedVertexAttribPointer::ScopedVertexAttribPointer(GLContext
* aGL
,
296 mAttribNormalized(0),
297 mAttribBufferBinding(0),
298 mAttribPointer(nullptr),
303 void ScopedVertexAttribPointer::WrapImpl(GLuint index
) {
304 mAttribIndex
= index
;
307 * mGL->fGetVertexAttribiv takes:
308 * VERTEX_ATTRIB_ARRAY_ENABLED
309 * VERTEX_ATTRIB_ARRAY_SIZE,
310 * VERTEX_ATTRIB_ARRAY_STRIDE,
311 * VERTEX_ATTRIB_ARRAY_TYPE,
312 * VERTEX_ATTRIB_ARRAY_NORMALIZED,
313 * VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
314 * CURRENT_VERTEX_ATTRIB
316 * CURRENT_VERTEX_ATTRIB is vertex shader state. \o/
317 * Others appear to be vertex array state,
318 * or alternatively in the internal vertex array state
319 * for a buffer object.
322 mGL
->fGetVertexAttribiv(mAttribIndex
, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED
,
324 mGL
->fGetVertexAttribiv(mAttribIndex
, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE
,
326 mGL
->fGetVertexAttribiv(mAttribIndex
, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE
,
328 mGL
->fGetVertexAttribiv(mAttribIndex
, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE
,
330 mGL
->fGetVertexAttribiv(mAttribIndex
, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED
,
332 mGL
->fGetVertexAttribiv(mAttribIndex
,
333 LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING
,
334 &mAttribBufferBinding
);
335 mGL
->fGetVertexAttribPointerv(
336 mAttribIndex
, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER
, &mAttribPointer
);
338 // Note that uniform values are program state, so we don't need to rebind
341 mGL
->GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING
, &mBoundBuffer
);
344 ScopedVertexAttribPointer::~ScopedVertexAttribPointer() {
345 mGL
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, mAttribBufferBinding
);
346 mGL
->fVertexAttribPointer(mAttribIndex
, mAttribSize
, mAttribType
,
347 mAttribNormalized
, mAttribStride
, mAttribPointer
);
349 mGL
->fEnableVertexAttribArray(mAttribIndex
);
351 mGL
->fDisableVertexAttribArray(mAttribIndex
);
352 mGL
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, mBoundBuffer
);
355 ////////////////////////////////////////////////////////////////////////
358 ScopedPackState::ScopedPackState(GLContext
* gl
)
365 mGL
->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT
, &mAlignment
);
367 if (mAlignment
!= 4) mGL
->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT
, 4);
369 if (!mGL
->HasPBOState()) return;
371 mGL
->fGetIntegerv(LOCAL_GL_PIXEL_PACK_BUFFER_BINDING
, (GLint
*)&mPixelBuffer
);
372 mGL
->fGetIntegerv(LOCAL_GL_PACK_ROW_LENGTH
, &mRowLength
);
373 mGL
->fGetIntegerv(LOCAL_GL_PACK_SKIP_PIXELS
, &mSkipPixels
);
374 mGL
->fGetIntegerv(LOCAL_GL_PACK_SKIP_ROWS
, &mSkipRows
);
376 if (mPixelBuffer
!= 0) mGL
->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER
, 0);
377 if (mRowLength
!= 0) mGL
->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH
, 0);
378 if (mSkipPixels
!= 0) mGL
->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS
, 0);
379 if (mSkipRows
!= 0) mGL
->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS
, 0);
382 bool ScopedPackState::SetForWidthAndStrideRGBA(GLsizei aWidth
,
384 MOZ_ASSERT(aStride
% 4 == 0, "RGBA data should always be 4-byte aligned");
385 MOZ_ASSERT(aStride
/ 4 >= aWidth
, "Stride too small");
386 if (aStride
/ 4 == aWidth
) {
387 // No special handling needed.
390 if (mGL
->HasPBOState()) {
391 // HasPBOState implies support for GL_PACK_ROW_LENGTH.
392 mGL
->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH
, aStride
/ 4);
398 ScopedPackState::~ScopedPackState() {
399 mGL
->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT
, mAlignment
);
401 if (!mGL
->HasPBOState()) return;
403 mGL
->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER
, mPixelBuffer
);
404 mGL
->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH
, mRowLength
);
405 mGL
->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS
, mSkipPixels
);
406 mGL
->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS
, mSkipRows
);
409 ////////////////////////////////////////////////////////////////////////
412 ResetUnpackState::ResetUnpackState(GLContext
* gl
)
421 const auto fnReset
= [&](GLenum pname
, GLuint val
, GLuint
* const out_old
) {
422 mGL
->GetUIntegerv(pname
, out_old
);
423 if (*out_old
!= val
) {
424 mGL
->fPixelStorei(pname
, val
);
428 // Default is 4, but 1 is more useful.
429 fnReset(LOCAL_GL_UNPACK_ALIGNMENT
, 1, &mAlignment
);
431 if (!mGL
->HasPBOState()) return;
433 mGL
->GetUIntegerv(LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING
, &mPBO
);
434 if (mPBO
!= 0) mGL
->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER
, 0);
436 fnReset(LOCAL_GL_UNPACK_ROW_LENGTH
, 0, &mRowLength
);
437 fnReset(LOCAL_GL_UNPACK_IMAGE_HEIGHT
, 0, &mImageHeight
);
438 fnReset(LOCAL_GL_UNPACK_SKIP_PIXELS
, 0, &mSkipPixels
);
439 fnReset(LOCAL_GL_UNPACK_SKIP_ROWS
, 0, &mSkipRows
);
440 fnReset(LOCAL_GL_UNPACK_SKIP_IMAGES
, 0, &mSkipImages
);
443 ResetUnpackState::~ResetUnpackState() {
444 mGL
->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT
, mAlignment
);
446 if (!mGL
->HasPBOState()) return;
448 mGL
->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER
, mPBO
);
450 mGL
->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH
, mRowLength
);
451 mGL
->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT
, mImageHeight
);
452 mGL
->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS
, mSkipPixels
);
453 mGL
->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS
, mSkipRows
);
454 mGL
->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES
, mSkipImages
);
457 ////////////////////////////////////////////////////////////////////////
460 static GLuint
GetPBOBinding(GLContext
* gl
, GLenum target
) {
461 if (!gl
->HasPBOState()) return 0;
463 GLenum targetBinding
;
465 case LOCAL_GL_PIXEL_PACK_BUFFER
:
466 targetBinding
= LOCAL_GL_PIXEL_PACK_BUFFER_BINDING
;
469 case LOCAL_GL_PIXEL_UNPACK_BUFFER
:
470 targetBinding
= LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING
;
477 return gl
->GetIntAs
<GLuint
>(targetBinding
);
480 ScopedBindPBO::ScopedBindPBO(GLContext
* gl
, GLenum target
)
481 : mGL(gl
), mTarget(target
), mPBO(GetPBOBinding(mGL
, mTarget
)) {}
483 ScopedBindPBO::~ScopedBindPBO() {
484 if (!mGL
->HasPBOState()) return;
486 mGL
->fBindBuffer(mTarget
, mPBO
);
490 } /* namespace mozilla */