Bug 1874684 - Part 28: Return DateDuration from DifferenceISODateTime. r=mgaudet
[gecko.git] / gfx / gl / ScopedGLHelpers.cpp
blobd654cae1639377a62bb55f39eafebeb0a439c072
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"
8 #include "GLContext.h"
9 #include "ScopedGLHelpers.h"
11 namespace mozilla {
12 namespace gl {
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;
24 if (aNewState) {
25 mGL->fEnable(mCapability);
26 } else {
27 mGL->fDisable(mCapability);
31 ScopedGLState::ScopedGLState(GLContext* aGL, GLenum aCapability)
32 : mGL(aGL), mCapability(aCapability) {
33 mOldState = mGL->fIsEnabled(mCapability);
36 ScopedGLState::~ScopedGLState() {
37 if (mOldState) {
38 mGL->fEnable(mCapability);
39 } else {
40 mGL->fDisable(mCapability);
44 /* ScopedBindFramebuffer - Saves and restores with GetUserBoundFB and
45 * BindUserFB. */
47 void ScopedBindFramebuffer::Init() {
48 if (mGL->IsSupported(GLFeature::split_framebuffer)) {
49 mOldReadFB = mGL->GetReadFB();
50 mOldDrawFB = mGL->GetDrawFB();
51 } else {
52 mOldReadFB = mOldDrawFB = mGL->GetFB();
56 ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL) : mGL(aGL) {
57 Init();
60 ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL, GLuint aNewFB)
61 : mGL(aGL) {
62 Init();
63 mGL->BindFB(aNewFB);
66 ScopedBindFramebuffer::~ScopedBindFramebuffer() {
67 if (mOldReadFB == mOldDrawFB) {
68 mGL->BindFB(mOldDrawFB);
69 } else {
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); }
96 /* ScopedFramebuffer
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;
120 switch (texTarget) {
121 case LOCAL_GL_TEXTURE_2D:
122 bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D;
123 break;
125 case LOCAL_GL_TEXTURE_CUBE_MAP:
126 bindingTarget = LOCAL_GL_TEXTURE_BINDING_CUBE_MAP;
127 break;
129 case LOCAL_GL_TEXTURE_3D:
130 bindingTarget = LOCAL_GL_TEXTURE_BINDING_3D;
131 break;
133 case LOCAL_GL_TEXTURE_2D_ARRAY:
134 bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D_ARRAY;
135 break;
137 case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
138 bindingTarget = LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB;
139 break;
141 case LOCAL_GL_TEXTURE_EXTERNAL:
142 bindingTarget = LOCAL_GL_TEXTURE_BINDING_EXTERNAL;
143 break;
145 default:
146 MOZ_CRASH("bad texTarget");
149 GLuint ret = 0;
150 gl->GetUIntegerv(bindingTarget, &ret);
151 return ret;
154 ScopedBindTexture::ScopedBindTexture(GLContext* aGL, GLuint aNewTex,
155 GLenum aTarget)
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() {
165 mOldRB = 0;
166 mGL->GetUIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &mOldRB);
169 ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext* aGL) : mGL(aGL) {
170 Init();
173 ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext* aGL, GLuint aNewRB)
174 : mGL(aGL) {
175 Init();
176 mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, aNewRB);
179 ScopedBindRenderbuffer::~ScopedBindRenderbuffer() {
180 mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOldRB);
183 /* ScopedFramebufferForTexture ************************************************/
184 ScopedFramebufferForTexture::ScopedFramebufferForTexture(GLContext* aGL,
185 GLuint aTexture,
186 GLenum aTarget)
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) {
195 mComplete = true;
196 } else {
197 mGL->fDeleteFramebuffers(1, &mFB);
198 mFB = 0;
202 ScopedFramebufferForTexture::~ScopedFramebufferForTexture() {
203 if (!mFB) return;
205 mGL->fDeleteFramebuffers(1, &mFB);
206 mFB = 0;
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) {
222 mComplete = true;
223 } else {
224 mGL->fDeleteFramebuffers(1, &mFB);
225 mFB = 0;
229 ScopedFramebufferForRenderbuffer::~ScopedFramebufferForRenderbuffer() {
230 if (!mFB) return;
232 mGL->fDeleteFramebuffers(1, &mFB);
233 mFB = 0;
236 /* ScopedViewportRect *********************************************************/
238 ScopedViewportRect::ScopedViewportRect(GLContext* aGL, GLint x, GLint y,
239 GLsizei width, GLsizei height)
240 : mGL(aGL) {
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)
254 : mGL(aGL) {
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)
274 : mGL(aGL),
275 mAttribEnabled(0),
276 mAttribSize(0),
277 mAttribStride(0),
278 mAttribType(0),
279 mAttribNormalized(0),
280 mAttribBufferBinding(0),
281 mAttribPointer(nullptr),
282 mBoundBuffer(0) {
283 WrapImpl(index);
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,
290 GLuint index)
291 : mGL(aGL),
292 mAttribEnabled(0),
293 mAttribSize(0),
294 mAttribStride(0),
295 mAttribType(0),
296 mAttribNormalized(0),
297 mAttribBufferBinding(0),
298 mAttribPointer(nullptr),
299 mBoundBuffer(0) {
300 WrapImpl(index);
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,
323 &mAttribEnabled);
324 mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE,
325 &mAttribSize);
326 mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE,
327 &mAttribStride);
328 mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE,
329 &mAttribType);
330 mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
331 &mAttribNormalized);
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
339 // those.
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);
348 if (mAttribEnabled)
349 mGL->fEnableVertexAttribArray(mAttribIndex);
350 else
351 mGL->fDisableVertexAttribArray(mAttribIndex);
352 mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundBuffer);
355 ////////////////////////////////////////////////////////////////////////
356 // ScopedPackState
358 ScopedPackState::ScopedPackState(GLContext* gl)
359 : mGL(gl),
360 mAlignment(0),
361 mPixelBuffer(0),
362 mRowLength(0),
363 mSkipPixels(0),
364 mSkipRows(0) {
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,
383 GLsizei aStride) {
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.
388 return true;
390 if (mGL->HasPBOState()) {
391 // HasPBOState implies support for GL_PACK_ROW_LENGTH.
392 mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, aStride / 4);
393 return true;
395 return false;
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 ////////////////////////////////////////////////////////////////////////
410 // ResetUnpackState
412 ResetUnpackState::ResetUnpackState(GLContext* gl)
413 : mGL(gl),
414 mAlignment(0),
415 mPBO(0),
416 mRowLength(0),
417 mImageHeight(0),
418 mSkipPixels(0),
419 mSkipRows(0),
420 mSkipImages(0) {
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 ////////////////////////////////////////////////////////////////////////
458 // ScopedBindPBO
460 static GLuint GetPBOBinding(GLContext* gl, GLenum target) {
461 if (!gl->HasPBOState()) return 0;
463 GLenum targetBinding;
464 switch (target) {
465 case LOCAL_GL_PIXEL_PACK_BUFFER:
466 targetBinding = LOCAL_GL_PIXEL_PACK_BUFFER_BINDING;
467 break;
469 case LOCAL_GL_PIXEL_UNPACK_BUFFER:
470 targetBinding = LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING;
471 break;
473 default:
474 MOZ_CRASH();
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);
489 } /* namespace gl */
490 } /* namespace mozilla */