1 /*========================================================================= 2 3 Program: Visualization Toolkit 4 Module: vtkOpenGLState.h 5 6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 7 All rights reserved. 8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details. 9 10 This software is distributed WITHOUT ANY WARRANTY; without even 11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 12 PURPOSE. See the above copyright notice for more information. 13 14 =========================================================================*/ 15 /** 16 * @class vtkOpenGLState 17 * @brief OpenGL state storage 18 * 19 * vtkOpenGLState is a class designed to keep track of the state of 20 * an OpenGL context. Applications using VTK have so much control 21 * over the rendering process that is can be difficult in VTK code 22 * to know if the OpenGL state is correct for your code. The two 23 * traditional solutions have been to set everything yourself 24 * and to save and restore OpenGL state that you change. The former 25 * makes your code work, the latter helps prevent your code from 26 * breaking something else. The problem is that the former results 27 * in tons of redundant OpenGL calls and the later is done by querying 28 * the OpenGL state which can cause a pipeline sync/stall which is 29 * very slow. 30 * 31 * To address these issues this class stores OpenGL state for commonly 32 * used functions. Requests made to change state to the current 33 * state become no-ops. Queries of state can be done by querying the 34 * state stored in this class without impacting the OpenGL driver. 35 * 36 * This class is designed to hold all context related values and 37 * could just as well be considered a representation of the OpenGL 38 * context. 39 * 40 * To facilitate saving state and restoring it this class contains 41 * a number of nested classes named Scoped<glFunction> that store 42 * the state of that glFunction and when they go out of scope they restore 43 * it. This is useful when you want to change the OpenGL state and then 44 * automatically restore it when done. They can be used as follows 45 * 46 * { 47 * vtkOpenGLState *ostate = renWin->GetState(); 48 * vtkOpenGLState::ScopedglDepthMask dmsaved(ostate); 49 * // the prior state is now saved 50 * ... 51 * ostate->glDepthMask(GL_TRUE); // maybe change the state 52 * ... etc 53 * } // prior state will be restored here as it goes out of scope 54 * 55 * 56 * You must use this class to make state changing OpenGL class otherwise the 57 * results will be undefined. 58 * 59 * For convenience some OpenGL calls that do not impact state are also 60 * provided. 61 */ 62 63 #ifndef vtkOpenGLState_h 64 #define vtkOpenGLState_h 65 66 #include "vtkObject.h" 67 #include "vtkRenderingOpenGL2Module.h" // For export macro 68 #include <array> // for ivar 69 #include <list> // for ivar 70 #include <map> // for ivar 71 #include <stack> // for ivar 72 #include <string> // for ivar 73 74 class vtkOpenGLFramebufferObject; 75 class vtkOpenGLRenderWindow; 76 class vtkOpenGLShaderCache; 77 class vtkOpenGLVertexBufferObjectCache; 78 class vtkTextureObject; 79 class vtkTextureUnitManager; 80 81 class VTKRENDERINGOPENGL2_EXPORT vtkOpenGLState : public vtkObject 82 { 83 public: 84 static vtkOpenGLState* New(); 85 vtkTypeMacro(vtkOpenGLState, vtkObject); 86 void PrintSelf(ostream& os, vtkIndent indent) override; 87 88 ///@{ 89 // cached OpenGL methods. By calling these the context will check 90 // the current value prior to making the OpenGL call. This can reduce 91 // the burden on the driver. 92 // 93 void vtkglClearColor(float red, float green, float blue, float alpha); 94 void vtkglClearDepth(double depth); 95 void vtkglDepthFunc(unsigned int val); 96 void vtkglDepthMask(unsigned char flag); 97 void vtkglColorMask(unsigned char r, unsigned char g, unsigned char b, unsigned char a); 98 void vtkglViewport(int x, int y, int width, int height); 99 void vtkglScissor(int x, int y, int width, int height); 100 void vtkglEnable(unsigned int cap); 101 void vtkglDisable(unsigned int cap); vtkglBlendFunc(unsigned int sfactor,unsigned int dfactor)102 void vtkglBlendFunc(unsigned int sfactor, unsigned int dfactor) 103 { 104 this->vtkglBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor); 105 } 106 void vtkglBlendFuncSeparate(unsigned int sfactorRGB, unsigned int dfactorRGB, 107 unsigned int sfactorAlpha, unsigned int dfactorAlpha); 108 void vtkglBlendEquation(unsigned int val); 109 void vtkglBlendEquationSeparate(unsigned int col, unsigned int alpha); 110 void vtkglCullFace(unsigned int val); 111 void vtkglActiveTexture(unsigned int); 112 113 void vtkglBindFramebuffer(unsigned int target, unsigned int fb); 114 void vtkglDrawBuffer(unsigned int); 115 void vtkglDrawBuffers(unsigned int n, unsigned int*); 116 void vtkglReadBuffer(unsigned int); 117 118 void vtkglPointSize(float); 119 void vtkglLineWidth(float); 120 void vtkglStencilMaskSeparate(unsigned int face, unsigned int mask); 121 void vtkglStencilMask(unsigned int mask); 122 void vtkglStencilOpSeparate( 123 unsigned int face, unsigned int sfail, unsigned int dpfail, unsigned int dppass); 124 void vtkglStencilOp(unsigned int sfail, unsigned int dpfail, unsigned int dppass); 125 void vtkglStencilFuncSeparate(unsigned int face, unsigned int func, int ref, unsigned int mask); 126 void vtkglStencilFunc(unsigned int func, int ref, unsigned int mask); 127 128 void vtkBindFramebuffer(unsigned int target, vtkOpenGLFramebufferObject* fo); 129 void vtkDrawBuffers(unsigned int n, unsigned int*, vtkOpenGLFramebufferObject*); 130 void vtkReadBuffer(unsigned int, vtkOpenGLFramebufferObject*); 131 132 void vtkglPixelStorei(unsigned int, int); 133 ///@} 134 135 ///@{ 136 // Methods to reset the state to the current OpenGL context value. 137 // These methods are useful when interfacing with third party code 138 // that may have changed the opengl state. 139 // 140 void ResetGLClearColorState(); 141 void ResetGLClearDepthState(); 142 void ResetGLDepthFuncState(); 143 void ResetGLDepthMaskState(); 144 void ResetGLColorMaskState(); 145 void ResetGLViewportState(); 146 void ResetGLScissorState(); 147 void ResetGLBlendFuncState(); 148 void ResetGLBlendEquationState(); 149 void ResetGLCullFaceState(); 150 void ResetGLActiveTexture(); 151 ///@} 152 153 ///@{ 154 // OpenGL functions that we provide an API for even though they may 155 // not hold any state. 156 void vtkglClear(unsigned int mask); 157 ///@} 158 159 ///@{ 160 // Get methods that can be used to query state if the state is not cached 161 // they fall through and call the underlying opengl functions 162 void vtkglGetBooleanv(unsigned int pname, unsigned char* params); 163 void vtkglGetIntegerv(unsigned int pname, int* params); 164 void vtkglGetDoublev(unsigned int pname, double* params); 165 void vtkglGetFloatv(unsigned int pname, float* params); 166 ///@} 167 168 // convenience to get all 4 values at once 169 void GetBlendFuncState(int*); 170 171 // convenience to return a bool 172 // as opposed to a unsigned char 173 bool GetEnumState(unsigned int name); 174 175 // convenience method to set a enum (glEnable/glDisable) 176 void SetEnumState(unsigned int name, bool value); 177 178 /** 179 * convenience method to reset an enum state from current openGL context 180 */ 181 void ResetEnumState(unsigned int name); 182 183 // superclass for Scoped subclasses 184 template <typename T> 185 class VTKRENDERINGOPENGL2_EXPORT ScopedValue 186 { 187 public: ~ScopedValue()188 ~ScopedValue() // restore value 189 { 190 ((*this->State).*(this->Method))(this->Value); 191 } 192 193 protected: 194 vtkOpenGLState* State; 195 T Value; 196 void (vtkOpenGLState::*Method)(T); 197 }; 198 199 /** 200 * Activate a texture unit for this texture 201 */ 202 void ActivateTexture(vtkTextureObject*); 203 204 /** 205 * Deactivate a previously activated texture 206 */ 207 void DeactivateTexture(vtkTextureObject*); 208 209 /** 210 * Get the texture unit for a given texture object 211 */ 212 int GetTextureUnitForTexture(vtkTextureObject*); 213 214 /** 215 * Check to make sure no textures have been left active 216 */ 217 void VerifyNoActiveTextures(); 218 219 ///@{ 220 /** 221 * Store/Restore the current framebuffer bindings and buffers. 222 */ PushFramebufferBindings()223 void PushFramebufferBindings() 224 { 225 this->PushDrawFramebufferBinding(); 226 this->PushReadFramebufferBinding(); 227 } 228 void PushDrawFramebufferBinding(); 229 void PushReadFramebufferBinding(); 230 PopFramebufferBindings()231 void PopFramebufferBindings() 232 { 233 this->PopReadFramebufferBinding(); 234 this->PopDrawFramebufferBinding(); 235 } 236 void PopDrawFramebufferBinding(); 237 void PopReadFramebufferBinding(); 238 239 void ResetFramebufferBindings(); 240 ///@} 241 242 // Scoped classes you can use to save state 243 class VTKRENDERINGOPENGL2_EXPORT ScopedglDepthMask : public ScopedValue<unsigned char> 244 { 245 public: 246 ScopedglDepthMask(vtkOpenGLState* state); 247 }; 248 class VTKRENDERINGOPENGL2_EXPORT ScopedglClearColor : public ScopedValue<std::array<float, 4>> 249 { 250 public: 251 ScopedglClearColor(vtkOpenGLState* state); 252 }; 253 class VTKRENDERINGOPENGL2_EXPORT ScopedglColorMask 254 : public ScopedValue<std::array<unsigned char, 4>> 255 { 256 public: 257 ScopedglColorMask(vtkOpenGLState* state); 258 }; 259 class VTKRENDERINGOPENGL2_EXPORT ScopedglScissor : public ScopedValue<std::array<int, 4>> 260 { 261 public: 262 ScopedglScissor(vtkOpenGLState* state); 263 }; 264 class VTKRENDERINGOPENGL2_EXPORT ScopedglViewport : public ScopedValue<std::array<int, 4>> 265 { 266 public: 267 ScopedglViewport(vtkOpenGLState* state); 268 }; 269 class VTKRENDERINGOPENGL2_EXPORT ScopedglBlendFuncSeparate 270 : public ScopedValue<std::array<unsigned int, 4>> 271 { 272 public: 273 ScopedglBlendFuncSeparate(vtkOpenGLState* state); 274 }; 275 class VTKRENDERINGOPENGL2_EXPORT ScopedglDepthFunc : public ScopedValue<unsigned int> 276 { 277 public: 278 ScopedglDepthFunc(vtkOpenGLState* state); 279 }; 280 class VTKRENDERINGOPENGL2_EXPORT ScopedglActiveTexture : public ScopedValue<unsigned int> 281 { 282 public: 283 ScopedglActiveTexture(vtkOpenGLState* state); 284 }; 285 286 class ScopedglEnableDisable 287 { 288 public: ScopedglEnableDisable(vtkOpenGLState * state,unsigned int name)289 ScopedglEnableDisable(vtkOpenGLState* state, unsigned int name) 290 { 291 this->State = state; 292 this->Name = name; 293 unsigned char val; 294 this->State->vtkglGetBooleanv(name, &val); 295 this->Value = val == 1; 296 } ~ScopedglEnableDisable()297 ~ScopedglEnableDisable() // restore value 298 { 299 this->State->SetEnumState(this->Name, this->Value); 300 } 301 302 protected: 303 vtkOpenGLState* State; 304 unsigned int Name; 305 bool Value; 306 }; 307 308 /** 309 * Initialize OpenGL context using current state 310 */ 311 void Initialize(vtkOpenGLRenderWindow*); 312 313 /** 314 * Set the texture unit manager. 315 */ 316 void SetTextureUnitManager(vtkTextureUnitManager* textureUnitManager); 317 318 /** 319 * Returns its texture unit manager object. A new one will be created if one 320 * hasn't already been set up. 321 */ 322 vtkTextureUnitManager* GetTextureUnitManager(); 323 324 // get the shader program cache for this context 325 vtkGetObjectMacro(ShaderCache, vtkOpenGLShaderCache); 326 327 // get the vbo buffer cache for this context 328 vtkGetObjectMacro(VBOCache, vtkOpenGLVertexBufferObjectCache); 329 330 // set the VBO Cache to use for this state 331 // this allows two contexts to share VBOs 332 // basically this is OPenGL's support for shared 333 // lists 334 void SetVBOCache(vtkOpenGLVertexBufferObjectCache* val); 335 336 /** 337 * Get a mapping of vtk data types to native texture formats for this window 338 * we put this on the RenderWindow so that every texture does not have to 339 * build these structures themselves 340 */ 341 int GetDefaultTextureInternalFormat( 342 int vtktype, int numComponents, bool needInteger, bool needFloat, bool needSRGB); 343 344 /** 345 * Get the current stored state of the draw buffer and binding 346 */ 347 void GetCurrentDrawFramebufferState(unsigned int& drawBinding, unsigned int& drawBuffer); 348 349 /** 350 * Perform a blit but handle some driver bugs safely. Use this instead of directly calling 351 * glBlitFrambuffer. 352 */ 353 void vtkglBlitFramebuffer(int, int, int, int, int, int, int, int, unsigned int, unsigned int); 354 355 /** 356 * Record the OpenGL state into this class. Lots of get calls so probably 357 * a pipeline stall. This method is most useful when integrating VTK with 358 * something else that touches OpenGL such as a GUI library or external 359 * OpenGL code. As OpenGL has a lot of state it is easy for VTK and 360 * external libraries to interfere with each other by changing that state. 361 * When extrnal code is calling VTK you would typically call Reset() 362 * Push() Pop() Reset will record the current state from OpenGL. Push 363 * saves it on the stack. Pop pops it from the stack and reapplies it to 364 * OpenGL so that the state is the same as when Pushed. Note that OpenGL 365 * has an incredible amount of state. This class only handles the values 366 * that VTK is known to touch. If you find other values that need saving 367 * please feel free to report an issue or provide an MR. 368 */ 369 void Reset(); 370 371 /** 372 * Push all the recorded state onto the stack. Typically called after a 373 * Reset. Not generally used internally in VTK as it is rarely required to 374 * save more than a couple state settings within VTKs render process. 375 */ 376 void Push(); 377 378 /** 379 * Pop the state stack to restore a previous state. At the end of this 380 * method OpenGL state will be set to the new popped state. 381 */ 382 void Pop(); 383 384 /** 385 * Return the opengl version for this context 386 */ GetVersion()387 std::string const& GetVersion() { return this->Version; } 388 389 /** 390 * Return the opengl vendor for this context 391 */ GetVendor()392 std::string const& GetVendor() { return this->Vendor; } 393 394 /** 395 * Return the opengl renderer for this context. Note this is 396 * the renderer opengl property, not a vtk renderer. 397 */ GetRenderer()398 std::string const& GetRenderer() { return this->Renderer; } 399 400 protected: 401 vtkOpenGLState(); // set initial values 402 ~vtkOpenGLState() override; 403 404 void BlendFuncSeparate(std::array<unsigned int, 4> val); 405 void ClearColor(std::array<float, 4> val); 406 void ColorMask(std::array<unsigned char, 4> val); 407 void Scissor(std::array<int, 4> val); 408 void Viewport(std::array<int, 4> val); 409 410 int TextureInternalFormats[VTK_UNICODE_STRING][3][5]; 411 void InitializeTextureInternalFormats(); 412 413 vtkTextureUnitManager* TextureUnitManager; 414 std::map<const vtkTextureObject*, int> TextureResourceIds; 415 416 /** 417 * Check that this OpenGL state has consistent values 418 * with the current OpenGL context 419 */ 420 void CheckState(); 421 422 // framebuffers hold state themselves 423 // specifically they hold their draw and read buffers 424 // and when bound they reinstate those buffers 425 class VTKRENDERINGOPENGL2_EXPORT BufferBindingState 426 { 427 public: 428 BufferBindingState(); 429 unsigned int Binding; 430 unsigned int ReadBuffer; 431 unsigned int DrawBuffers[10]; 432 unsigned int GetBinding(); 433 unsigned int GetDrawBuffer(unsigned int); 434 unsigned int GetReadBuffer(); 435 }; 436 std::list<BufferBindingState> DrawBindings; 437 std::list<BufferBindingState> ReadBindings; 438 439 // static opengl properties 440 int MajorVersion; 441 int MinorVersion; 442 int MaxTextureSize; 443 std::string Vendor; 444 std::string Renderer; 445 std::string Version; 446 447 class VTKRENDERINGOPENGL2_EXPORT GLState 448 { 449 public: 450 double ClearDepth; 451 unsigned char DepthMask; 452 unsigned int DepthFunc; 453 unsigned int BlendEquationValue1; 454 unsigned int BlendEquationValue2; 455 unsigned int CullFaceMode; 456 unsigned int ActiveTexture; 457 458 float PointSize; 459 float LineWidth; 460 unsigned int StencilMaskFront; 461 unsigned int StencilMaskBack; 462 std::array<unsigned int, 3> StencilFuncFront; 463 std::array<unsigned int, 3> StencilFuncBack; 464 std::array<unsigned int, 3> StencilOpFront; 465 std::array<unsigned int, 3> StencilOpBack; 466 467 int PackAlignment; 468 int UnpackAlignment; 469 int UnpackRowLength; 470 int UnpackImageHeight; 471 472 std::array<float, 4> ClearColor; 473 std::array<unsigned char, 4> ColorMask; 474 std::array<int, 4> Viewport; 475 std::array<int, 4> Scissor; 476 std::array<unsigned int, 4> BlendFunc; 477 bool DepthTest; 478 bool CullFace; 479 bool ScissorTest; 480 bool StencilTest; 481 bool Blend; 482 bool MultiSample; 483 bool CubeMapSeamless; 484 bool LineSmooth; 485 int BoundVAO; 486 int BoundArrayBuffer; 487 int BoundElementArrayBuffer; 488 int BoundProgram; 489 BufferBindingState DrawBinding; 490 BufferBindingState ReadBinding; 491 GLState() = default; 492 }; 493 494 std::stack<GLState> Stack; 495 496 vtkOpenGLVertexBufferObjectCache* VBOCache; 497 vtkOpenGLShaderCache* ShaderCache; 498 499 private: 500 vtkOpenGLState(const vtkOpenGLState&) = delete; 501 void operator=(const vtkOpenGLState&) = delete; 502 }; 503 504 #endif 505