ScopedGLHelpers.cpp (15266B)
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/. */ 5 6 #include "GLContext.h" 7 #include "ScopedGLHelpers.h" 8 9 namespace mozilla { 10 namespace gl { 11 12 /* ScopedGLState - Wraps glEnable/glDisable. **********************************/ 13 14 // Use |newState = true| to enable, |false| to disable. 15 ScopedGLState::ScopedGLState(GLContext* aGL, GLenum aCapability, bool aNewState) 16 : mGL(aGL), mCapability(aCapability) { 17 mOldState = mGL->fIsEnabled(mCapability); 18 19 // Early out if we're already in the right state. 20 if (aNewState == mOldState) return; 21 22 if (aNewState) { 23 mGL->fEnable(mCapability); 24 } else { 25 mGL->fDisable(mCapability); 26 } 27 } 28 29 ScopedGLState::ScopedGLState(GLContext* aGL, GLenum aCapability) 30 : mGL(aGL), mCapability(aCapability) { 31 mOldState = mGL->fIsEnabled(mCapability); 32 } 33 34 ScopedGLState::~ScopedGLState() { 35 if (mOldState) { 36 mGL->fEnable(mCapability); 37 } else { 38 mGL->fDisable(mCapability); 39 } 40 } 41 42 /* ScopedBindFramebuffer - Saves and restores with GetUserBoundFB and 43 * BindUserFB. */ 44 45 void ScopedBindFramebuffer::Init() { 46 if (mGL->IsSupported(GLFeature::split_framebuffer)) { 47 mOldReadFB = mGL->GetReadFB(); 48 mOldDrawFB = mGL->GetDrawFB(); 49 } else { 50 mOldReadFB = mOldDrawFB = mGL->GetFB(); 51 } 52 } 53 54 ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL) : mGL(aGL) { 55 Init(); 56 } 57 58 ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL, GLuint aNewFB) 59 : mGL(aGL) { 60 Init(); 61 mGL->BindFB(aNewFB); 62 } 63 64 ScopedBindFramebuffer::~ScopedBindFramebuffer() { 65 if (mOldReadFB == mOldDrawFB) { 66 mGL->BindFB(mOldDrawFB); 67 } else { 68 mGL->BindDrawFB(mOldDrawFB); 69 mGL->BindReadFB(mOldReadFB); 70 } 71 } 72 73 /* ScopedBindTextureUnit ******************************************************/ 74 75 ScopedBindTextureUnit::ScopedBindTextureUnit(GLContext* aGL, GLenum aTexUnit) 76 : mGL(aGL), mOldTexUnit(0) { 77 MOZ_ASSERT(aTexUnit >= LOCAL_GL_TEXTURE0); 78 mGL->GetUIntegerv(LOCAL_GL_ACTIVE_TEXTURE, &mOldTexUnit); 79 mGL->fActiveTexture(aTexUnit); 80 } 81 82 ScopedBindTextureUnit::~ScopedBindTextureUnit() { 83 mGL->fActiveTexture(mOldTexUnit); 84 } 85 86 /* ScopedTexture **************************************************************/ 87 88 ScopedTexture::ScopedTexture(GLContext* aGL) : mGL(aGL), mTexture(0) { 89 mGL->fGenTextures(1, &mTexture); 90 } 91 92 ScopedTexture::~ScopedTexture() { mGL->fDeleteTextures(1, &mTexture); } 93 94 /* ScopedFramebuffer 95 * **************************************************************/ 96 97 ScopedFramebuffer::ScopedFramebuffer(GLContext* aGL) : mGL(aGL), mFB(0) { 98 mGL->fGenFramebuffers(1, &mFB); 99 } 100 101 ScopedFramebuffer::~ScopedFramebuffer() { mGL->fDeleteFramebuffers(1, &mFB); } 102 103 /* ScopedRenderbuffer 104 * **************************************************************/ 105 106 ScopedRenderbuffer::ScopedRenderbuffer(GLContext* aGL) : mGL(aGL), mRB(0) { 107 mGL->fGenRenderbuffers(1, &mRB); 108 } 109 110 ScopedRenderbuffer::~ScopedRenderbuffer() { 111 mGL->fDeleteRenderbuffers(1, &mRB); 112 } 113 114 /* ScopedBindTexture **********************************************************/ 115 116 static GLuint GetBoundTexture(GLContext* gl, GLenum texTarget) { 117 GLenum bindingTarget; 118 switch (texTarget) { 119 case LOCAL_GL_TEXTURE_2D: 120 bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D; 121 break; 122 123 case LOCAL_GL_TEXTURE_CUBE_MAP: 124 bindingTarget = LOCAL_GL_TEXTURE_BINDING_CUBE_MAP; 125 break; 126 127 case LOCAL_GL_TEXTURE_3D: 128 bindingTarget = LOCAL_GL_TEXTURE_BINDING_3D; 129 break; 130 131 case LOCAL_GL_TEXTURE_2D_ARRAY: 132 bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D_ARRAY; 133 break; 134 135 case LOCAL_GL_TEXTURE_RECTANGLE_ARB: 136 bindingTarget = LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB; 137 break; 138 139 case LOCAL_GL_TEXTURE_EXTERNAL: 140 bindingTarget = LOCAL_GL_TEXTURE_BINDING_EXTERNAL; 141 break; 142 143 default: 144 MOZ_CRASH("bad texTarget"); 145 } 146 147 GLuint ret = 0; 148 gl->GetUIntegerv(bindingTarget, &ret); 149 return ret; 150 } 151 152 ScopedBindTexture::ScopedBindTexture(GLContext* aGL, GLuint aNewTex, 153 GLenum aTarget) 154 : mGL(aGL), mTarget(aTarget), mOldTex(GetBoundTexture(aGL, aTarget)) { 155 mGL->fBindTexture(mTarget, aNewTex); 156 } 157 158 ScopedBindTexture::~ScopedBindTexture() { mGL->fBindTexture(mTarget, mOldTex); } 159 160 /* ScopedBindRenderbuffer *****************************************************/ 161 162 void ScopedBindRenderbuffer::Init() { 163 mOldRB = 0; 164 mGL->GetUIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &mOldRB); 165 } 166 167 ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext* aGL) : mGL(aGL) { 168 Init(); 169 } 170 171 ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext* aGL, GLuint aNewRB) 172 : mGL(aGL) { 173 Init(); 174 mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, aNewRB); 175 } 176 177 ScopedBindRenderbuffer::~ScopedBindRenderbuffer() { 178 mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOldRB); 179 } 180 181 /* ScopedFramebufferForTexture ************************************************/ 182 ScopedFramebufferForTexture::ScopedFramebufferForTexture(GLContext* aGL, 183 GLuint aTexture, 184 GLenum aTarget) 185 : mGL(aGL), mComplete(false), mFB(0) { 186 mGL->fGenFramebuffers(1, &mFB); 187 ScopedBindFramebuffer autoFB(aGL, mFB); 188 mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, 189 aTarget, aTexture, 0); 190 191 GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); 192 if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) { 193 mComplete = true; 194 } else { 195 mGL->fDeleteFramebuffers(1, &mFB); 196 mFB = 0; 197 } 198 } 199 200 ScopedFramebufferForTexture::~ScopedFramebufferForTexture() { 201 if (!mFB) return; 202 203 mGL->fDeleteFramebuffers(1, &mFB); 204 mFB = 0; 205 } 206 207 /* ScopedFramebufferForRenderbuffer *******************************************/ 208 209 ScopedFramebufferForRenderbuffer::ScopedFramebufferForRenderbuffer( 210 GLContext* aGL, GLuint aRB) 211 : mGL(aGL), mComplete(false), mFB(0) { 212 mGL->fGenFramebuffers(1, &mFB); 213 ScopedBindFramebuffer autoFB(aGL, mFB); 214 mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, 215 LOCAL_GL_COLOR_ATTACHMENT0, 216 LOCAL_GL_RENDERBUFFER, aRB); 217 218 GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); 219 if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) { 220 mComplete = true; 221 } else { 222 mGL->fDeleteFramebuffers(1, &mFB); 223 mFB = 0; 224 } 225 } 226 227 ScopedFramebufferForRenderbuffer::~ScopedFramebufferForRenderbuffer() { 228 if (!mFB) return; 229 230 mGL->fDeleteFramebuffers(1, &mFB); 231 mFB = 0; 232 } 233 234 /* ScopedViewportRect *********************************************************/ 235 236 ScopedViewportRect::ScopedViewportRect(GLContext* aGL, GLint x, GLint y, 237 GLsizei width, GLsizei height) 238 : mGL(aGL) { 239 mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, mSavedViewportRect); 240 mGL->fViewport(x, y, width, height); 241 } 242 243 ScopedViewportRect::~ScopedViewportRect() { 244 mGL->fViewport(mSavedViewportRect[0], mSavedViewportRect[1], 245 mSavedViewportRect[2], mSavedViewportRect[3]); 246 } 247 248 /* ScopedScissorRect **********************************************************/ 249 250 ScopedScissorRect::ScopedScissorRect(GLContext* aGL, GLint x, GLint y, 251 GLsizei width, GLsizei height) 252 : mGL(aGL) { 253 mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect); 254 mGL->fScissor(x, y, width, height); 255 } 256 257 ScopedScissorRect::ScopedScissorRect(GLContext* aGL) : mGL(aGL) { 258 mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect); 259 } 260 261 ScopedScissorRect::~ScopedScissorRect() { 262 mGL->fScissor(mSavedScissorRect[0], mSavedScissorRect[1], 263 mSavedScissorRect[2], mSavedScissorRect[3]); 264 } 265 266 /* ScopedVertexAttribPointer **************************************************/ 267 268 ScopedVertexAttribPointer::ScopedVertexAttribPointer( 269 GLContext* aGL, GLuint index, GLint size, GLenum type, 270 realGLboolean normalized, GLsizei stride, GLuint buffer, 271 const GLvoid* pointer) 272 : mGL(aGL), 273 mAttribEnabled(0), 274 mAttribSize(0), 275 mAttribStride(0), 276 mAttribType(0), 277 mAttribNormalized(0), 278 mAttribBufferBinding(0), 279 mAttribPointer(nullptr), 280 mBoundBuffer(0) { 281 WrapImpl(index); 282 mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer); 283 mGL->fVertexAttribPointer(index, size, type, normalized, stride, pointer); 284 mGL->fEnableVertexAttribArray(index); 285 } 286 287 ScopedVertexAttribPointer::ScopedVertexAttribPointer(GLContext* aGL, 288 GLuint index) 289 : mGL(aGL), 290 mAttribEnabled(0), 291 mAttribSize(0), 292 mAttribStride(0), 293 mAttribType(0), 294 mAttribNormalized(0), 295 mAttribBufferBinding(0), 296 mAttribPointer(nullptr), 297 mBoundBuffer(0) { 298 WrapImpl(index); 299 } 300 301 void ScopedVertexAttribPointer::WrapImpl(GLuint index) { 302 mAttribIndex = index; 303 304 /* 305 * mGL->fGetVertexAttribiv takes: 306 * VERTEX_ATTRIB_ARRAY_ENABLED 307 * VERTEX_ATTRIB_ARRAY_SIZE, 308 * VERTEX_ATTRIB_ARRAY_STRIDE, 309 * VERTEX_ATTRIB_ARRAY_TYPE, 310 * VERTEX_ATTRIB_ARRAY_NORMALIZED, 311 * VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, 312 * CURRENT_VERTEX_ATTRIB 313 * 314 * CURRENT_VERTEX_ATTRIB is vertex shader state. \o/ 315 * Others appear to be vertex array state, 316 * or alternatively in the internal vertex array state 317 * for a buffer object. 318 */ 319 320 mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED, 321 &mAttribEnabled); 322 mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE, 323 &mAttribSize); 324 mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE, 325 &mAttribStride); 326 mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE, 327 &mAttribType); 328 mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, 329 &mAttribNormalized); 330 mGL->fGetVertexAttribiv(mAttribIndex, 331 LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, 332 &mAttribBufferBinding); 333 mGL->fGetVertexAttribPointerv( 334 mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER, &mAttribPointer); 335 336 // Note that uniform values are program state, so we don't need to rebind 337 // those. 338 339 mGL->GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING, &mBoundBuffer); 340 } 341 342 ScopedVertexAttribPointer::~ScopedVertexAttribPointer() { 343 mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mAttribBufferBinding); 344 mGL->fVertexAttribPointer(mAttribIndex, mAttribSize, mAttribType, 345 mAttribNormalized, mAttribStride, mAttribPointer); 346 if (mAttribEnabled) 347 mGL->fEnableVertexAttribArray(mAttribIndex); 348 else 349 mGL->fDisableVertexAttribArray(mAttribIndex); 350 mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundBuffer); 351 } 352 353 //////////////////////////////////////////////////////////////////////// 354 // ScopedPackState 355 356 ScopedPackState::ScopedPackState(GLContext* gl) 357 : mGL(gl), 358 mAlignment(0), 359 mPixelBuffer(0), 360 mRowLength(0), 361 mSkipPixels(0), 362 mSkipRows(0) { 363 mGL->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &mAlignment); 364 365 if (mAlignment != 4) mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4); 366 367 if (!mGL->HasPBOState()) return; 368 369 mGL->fGetIntegerv(LOCAL_GL_PIXEL_PACK_BUFFER_BINDING, (GLint*)&mPixelBuffer); 370 mGL->fGetIntegerv(LOCAL_GL_PACK_ROW_LENGTH, &mRowLength); 371 mGL->fGetIntegerv(LOCAL_GL_PACK_SKIP_PIXELS, &mSkipPixels); 372 mGL->fGetIntegerv(LOCAL_GL_PACK_SKIP_ROWS, &mSkipRows); 373 374 if (mPixelBuffer != 0) mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, 0); 375 if (mRowLength != 0) mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, 0); 376 if (mSkipPixels != 0) mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, 0); 377 if (mSkipRows != 0) mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, 0); 378 } 379 380 bool ScopedPackState::SetForWidthAndStrideRGBA(GLsizei aWidth, 381 GLsizei aStride) { 382 MOZ_ASSERT(aStride % 4 == 0, "RGBA data should always be 4-byte aligned"); 383 MOZ_ASSERT(aStride / 4 >= aWidth, "Stride too small"); 384 if (aStride / 4 == aWidth) { 385 // No special handling needed. 386 return true; 387 } 388 if (mGL->HasPBOState()) { 389 // HasPBOState implies support for GL_PACK_ROW_LENGTH. 390 mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, aStride / 4); 391 return true; 392 } 393 return false; 394 } 395 396 ScopedPackState::~ScopedPackState() { 397 mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mAlignment); 398 399 if (!mGL->HasPBOState()) return; 400 401 mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, mPixelBuffer); 402 mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mRowLength); 403 mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mSkipPixels); 404 mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mSkipRows); 405 } 406 407 //////////////////////////////////////////////////////////////////////// 408 // ResetUnpackState 409 410 ResetUnpackState::ResetUnpackState(GLContext* gl) 411 : mGL(gl), 412 mAlignment(0), 413 mPBO(0), 414 mRowLength(0), 415 mImageHeight(0), 416 mSkipPixels(0), 417 mSkipRows(0), 418 mSkipImages(0) { 419 const auto fnReset = [&](GLenum pname, GLuint val, GLuint* const out_old) { 420 mGL->GetUIntegerv(pname, out_old); 421 if (*out_old != val) { 422 mGL->fPixelStorei(pname, val); 423 } 424 }; 425 426 // Default is 4, but 1 is more useful. 427 fnReset(LOCAL_GL_UNPACK_ALIGNMENT, 1, &mAlignment); 428 429 if (!mGL->HasPBOState()) return; 430 431 mGL->GetUIntegerv(LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING, &mPBO); 432 if (mPBO != 0) mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0); 433 434 fnReset(LOCAL_GL_UNPACK_ROW_LENGTH, 0, &mRowLength); 435 fnReset(LOCAL_GL_UNPACK_IMAGE_HEIGHT, 0, &mImageHeight); 436 fnReset(LOCAL_GL_UNPACK_SKIP_PIXELS, 0, &mSkipPixels); 437 fnReset(LOCAL_GL_UNPACK_SKIP_ROWS, 0, &mSkipRows); 438 fnReset(LOCAL_GL_UNPACK_SKIP_IMAGES, 0, &mSkipImages); 439 } 440 441 ResetUnpackState::~ResetUnpackState() { 442 mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, mAlignment); 443 444 if (!mGL->HasPBOState()) return; 445 446 mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPBO); 447 448 mGL->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, mRowLength); 449 mGL->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, mImageHeight); 450 mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS, mSkipPixels); 451 mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, mSkipRows); 452 mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, mSkipImages); 453 } 454 455 //////////////////////////////////////////////////////////////////////// 456 // ScopedBindPBO 457 458 static GLuint GetPBOBinding(GLContext* gl, GLenum target) { 459 if (!gl->HasPBOState()) return 0; 460 461 GLenum targetBinding; 462 switch (target) { 463 case LOCAL_GL_PIXEL_PACK_BUFFER: 464 targetBinding = LOCAL_GL_PIXEL_PACK_BUFFER_BINDING; 465 break; 466 467 case LOCAL_GL_PIXEL_UNPACK_BUFFER: 468 targetBinding = LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING; 469 break; 470 471 default: 472 MOZ_CRASH(); 473 } 474 475 return gl->GetIntAs<GLuint>(targetBinding); 476 } 477 478 ScopedBindPBO::ScopedBindPBO(GLContext* gl, GLenum target) 479 : mGL(gl), mTarget(target), mPBO(GetPBOBinding(mGL, mTarget)) {} 480 481 ScopedBindPBO::~ScopedBindPBO() { 482 if (!mGL->HasPBOState()) return; 483 484 mGL->fBindBuffer(mTarget, mPBO); 485 } 486 487 } /* namespace gl */ 488 } /* namespace mozilla */