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