1 /*
2 A* -------------------------------------------------------------------
3 B* This file contains source code for the PyMOL computer program
4 C* copyright Schrodinger, LLC.
5 D* -------------------------------------------------------------------
6 E* It is unlawful to modify or remove this copyright notice.
7 F* -------------------------------------------------------------------
8 G* Please see the accompanying LICENSE file for further information.
9 H* -------------------------------------------------------------------
10 I* Additional authors of this source file include:
11 -*
12 -*
13 -*
14 Z* -------------------------------------------------------------------
15 */
16 #ifndef _SHADER_MGR_H
17 #define _SHADER_MGR_H
18 
19 #include "os_gl.h"
20 #include "PyMOLGlobals.h"
21 #include "Executive_pre.h"
22 #include "OVContext.h"
23 #include "Rep.h"
24 #include "GenericBuffer.h"
25 #include "SceneDef.h"
26 #include "PostProcess.h"
27 #include <map>
28 #include <set>
29 #include <string>
30 #include <unordered_map>
31 
32 #ifdef _WEBGL
33 #define GET_FRAGDEPTH_SUPPORT() webpymol_get_fragdepth_support()
34 #elif defined(_PYMOL_IOS)
35 #define GET_FRAGDEPTH_SUPPORT() 0
36 #else
37 #define GET_FRAGDEPTH_SUPPORT() 1
38 #endif
39 
40 #if !defined(_WEBGL)
41 #include <mutex>
42 #define LOCK_GUARD_MUTEX(name, var) std::lock_guard<std::mutex> name(var)
43 #else
44 #define LOCK_GUARD_MUTEX(name, var)
45 #endif
46 
47 #ifndef GL_FRAGMENT_PROGRAM_ARB
48 #define GL_FRAGMENT_PROGRAM_ARB                         0x8804
49 #endif
50 
51 /* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
52 #if 0
53 PFNGLTEXIMAGE3DPROC getTexImage3D();
54 static PFNGLTEXIMAGE3DPROC glTexImage3D;
55 static PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
56 static PFNGLBINDPROGRAMARBPROC glBindProgramARB;
57 static PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
58 static PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
59 static PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB;
60 static PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
61 #endif
62 /* END PROPRIETARY CODE SEGMENT */
63 
64 class CShaderPrg {
65 public:
66   const std::string name, geomfile, vertfile, fragfile;
67 
68   std::map<int, std::string> uniformLocations;
69 
70   GLenum gsInput, gsOutput;
71   int ngsVertsOut;
72 
73   std::string derivative;
74   bool is_valid;
75   bool is_linked;
76 
77   CShaderPrg(PyMOLGlobals * G_,
78              const std::string &name,
79              const std::string &vertfile,
80              const std::string &fragfile,
81              const std::string &geomfile = "",
82              GLenum gsInput = 0,
83              GLenum gsOutput = 0,
84              int ngsVertsOut = 0) :
name(name)85     name(name),
86     geomfile(geomfile), vertfile(vertfile), fragfile(fragfile),
87     gsInput(gsInput), gsOutput(gsOutput), ngsVertsOut(ngsVertsOut),
88     is_valid(false), is_linked(false), G(G_),
89     id(0), gid(0), vid(0), fid(0), uniform_set(0) {}
90 
~CShaderPrg()91   ~CShaderPrg() {}
92 
93   bool reload();
94 
95   /*
96    * Create a derivative copy. This will reload with ShaderMgr::Reload_Derivatives.
97    */
DerivativeCopy(const std::string & name,const std::string & variable)98   CShaderPrg * DerivativeCopy(const std::string &name, const std::string &variable) {
99     CShaderPrg * copy = new CShaderPrg(G, name, vertfile, fragfile, geomfile, gsInput, gsOutput, ngsVertsOut);
100     copy->derivative = variable;
101     return copy;
102   }
103 
104 #ifdef _PYMOL_ARB_SHADERS
105   static CShaderPrg *NewARB(PyMOLGlobals * G, const char * name, const std::string& vert, const std::string& frag);
106   int DisableARB();
107 #endif
108 
109 /* Enable */
110   int Enable();
111 
112 /* Disable */
113   int Disable();
114 
115 /* Link and IsLinked */
116   int Link();
117   int IsLinked();
118 
119 /* accessors/mutators/uniform setters */
120   int Set1i(const char * name, int i);
121   int Set1f(const char * name, float f);
122   int Set2f(const char * name, float f1, float f2);
123   int Set3f(const char * name, float f1, float f2, float f3);
124   int Set4fv(const char * name, const float *f);
125   int Set3fv(const char * name, const float *f);
126   int Set4f(const char * name, float f1, float f2, float f3, float f4);
127   int SetMat3fc(const char * name, const GLfloat * m);
128   int SetMat4fc(const char * name, const GLfloat * m);
129 
130   int GetUniformLocation(const char * name);
131   int GetAttribLocation(const char * name);
132   void SetAttrib4fLocation(const char * name, float f1, float f2, float f3, float f4);
133   void SetAttrib1fLocation(const char * name, float f1);
134 
135   int SetLightingEnabled(int);
136   void SetBgUniforms();
137   void Set_Stereo_And_AnaglyphMode();
138   void Set_AnaglyphMode(int mode);
139   void Set_Matrices();
140   void Set_Specular_Values();
141 
142   void Invalidate();
143   void ErrorMsgWithShaderInfoLog(const GLuint sid, const char * msg);
144 
145 public:
146   PyMOLGlobals * G;
147 
148   /* openGL assigned id */
149   int id;
150 
151   /* openGL fragment and vertex shader ids */
152   GLuint gid;
153   GLuint vid;
154   GLuint fid;
155 
156   std::map<std::string, int> uniforms;
157   std::map<std::string, int> attributes;
158 
159   int uniform_set ; // bitmask
160 };
161 
162 /* ============================================================================
163  * CShaderMgr class -- simple ShaderMgr for PyMOL
164  * ============================================================================*/
165 class CShaderMgr {
166 public:
167   CShaderMgr(PyMOLGlobals * G);
168   ~CShaderMgr();
169 
170   void Config();
171   void Set_Reload_Bits(int bits);
172   void Check_Reload();
173   GLfloat *GetLineWidthRange();
174 
175   template <typename T, typename... TArgs>
newGPUBuffer(TArgs &&...args)176   T * newGPUBuffer(TArgs&&... args) {
177     std::hash<gpuBuffer_t *> hash_fn;
178     T * buffer = new T(std::forward<TArgs>(args)...);
179     auto bufptr = dynamic_cast<gpuBuffer_t *>(buffer);
180     const size_t hashid = hash_fn(bufptr);
181     buffer->set_hash_id(hashid);
182     _gpu_object_map[hashid] = buffer;
183     return buffer;
184   }
185 
186   template <typename T>
getGPUBuffer(size_t hashid)187   T * getGPUBuffer(size_t hashid) {
188     auto search = _gpu_object_map.find(hashid);
189     if (search != _gpu_object_map.end())
190       return dynamic_cast<T*>(search->second);
191     else
192       return nullptr;
193   }
194 
195   void bindGPUBuffer(size_t hashid);
196   void freeGPUBuffer(size_t handle);
197   void freeGPUBuffers(std::vector<size_t> && handles);
198   void freeGPUBuffers(size_t * arr, size_t len);
199 
200 #ifndef _PYMOL_NO_AA_SHADERS
201   bool Reload_SMAA_Shaders();
202   int SMAAShadersPresent();
203   CShaderPrg *Enable_FXAAShader();
204   CShaderPrg *Enable_SMAA1Shader();
205   CShaderPrg *Enable_SMAA2Shader();
206   CShaderPrg *Enable_SMAA3Shader();
207   CShaderPrg *Enable_SMAAShader(const char *shaderName);
208 #endif
209   void Reload_Shader_Variables();
210 
211 /* AddShader -- Adds to the global shader library */
212   int AddShaderPrg(CShaderPrg * s);
213 
214 /* RemoveShader -- Removes shader program by name */
215   int RemoveShaderPrg(const std::string& name);
216 
217 /* GetShaderPrg -- gets a ptr to the installed shader */
218   CShaderPrg * GetShaderPrg(std::string name, short set_current_shader = 1, short pass = 0);
219 
220   int ShaderPrgExists(const char * name);
221 
222 /* runtime check for shaders */
223   int ShadersPresent();
224   int GeometryShadersPresent();
225 
226   void AddVBOsToFree(GLuint *vboid, int nvbos);
227   void AddVBOToFree(GLuint vboid);
228   void FreeAllVBOs();
229 
230   CShaderPrg *Enable_DefaultShader(int pass);
231   CShaderPrg *Enable_LineShader(int pass);
232   CShaderPrg *Enable_SurfaceShader(int pass);
233   CShaderPrg *Enable_DefaultShaderWithSettings(const CSetting * set1, const CSetting * set2, int pass);
234   CShaderPrg *Enable_CylinderShader(const char *, int pass);
235   CShaderPrg *Enable_CylinderShader(int pass);
236   CShaderPrg *Enable_DefaultSphereShader(int pass);
237 #ifdef _PYMOL_ARB_SHADERS
238   CShaderPrg *Enable_SphereShaderARB();
239 #endif
240   CShaderPrg *Enable_RampShader();
241   CShaderPrg *Enable_ConnectorShader(int pass);
242   CShaderPrg *Enable_TriLinesShader();
243   CShaderPrg *Enable_ScreenShader();
244   CShaderPrg *Enable_LabelShader(int pass);
245   CShaderPrg *Enable_OITShader();
246   CShaderPrg *Enable_OITCopyShader();
247   CShaderPrg *Enable_IndicatorShader();
248   CShaderPrg *Enable_BackgroundShader();
249 
250   void Disable_Current_Shader();
251 
252   CShaderPrg *Get_ScreenShader();
253   CShaderPrg *Get_ConnectorShader(int pass);
254   CShaderPrg *Get_DefaultShader(int pass);
255   CShaderPrg *Get_LineShader(int pass);
256   CShaderPrg *Get_SurfaceShader(int pass);
257   CShaderPrg *Get_CylinderShader(int pass, short set_current_shader=1);
258   CShaderPrg *Get_CylinderNewShader(int pass, short set_current_shader=1);
259   CShaderPrg *Get_DefaultSphereShader(int pass);
260   CShaderPrg *Get_RampShader();
261   CShaderPrg *Get_Current_Shader();
262   CShaderPrg *Get_IndicatorShader();
263   CShaderPrg *Get_BackgroundShader();
264   CShaderPrg *Get_LabelShader(int pass);
265 
266   void Reload_CallComputeColorForLight();
267   void Reload_All_Shaders();
268 
269   void Invalidate_All_Shaders();
270 
271   void ResetUniformSet();
272 
273   void CShaderPrg_SetIsPicking(int is_picking);
274 
275   void Generate_LightingTexture();
276 
277   std::string GetShaderSource(const std::string &filename);
278 
279   CShaderPrg *Setup_LabelShader(CShaderPrg *shaderPrg);
280   CShaderPrg *Setup_DefaultShader(CShaderPrg *shaderPrg, const CSetting *set1, const CSetting *set2);
281 
282   void SetIsPicking(int is_picking);
283   int GetIsPicking();
284 
285   void SetPreprocVar(const std::string &key, bool value, bool invshaders = true);
286 
287 private:
288   void freeAllGPUBuffers();
289   void RegisterDependantFileNames(CShaderPrg * shader);
290   void CollectDependantFileNames(const std::string &filename, std::vector<std::string> &filenames);
291   void MakeDerivatives(const std::string &suffix, const std::string &variable);
292   void Reload_Derivatives(const std::string &variable, bool value = true);
293   void ShaderSourceInvalidate(const char * filename, bool invshaders = true);
294   void SetShaderSource(const char * filename, const std::string &contents);
295 
296 public:
297   PyMOLGlobals * G;
298   int shaders_present;
299 
300 #ifndef _WEBGL
301   // for deleting buffers in the correct thread
302   std::vector<GLuint> vbos_to_free;
303   std::mutex vbos_to_free_mutex;
304   std::mutex gpu_objects_to_free_mutex;
305 #endif
306 
307   CShaderPrg *current_shader;
308   int is_picking;
309   GLuint lightingTexture;
310 
311   /* These lookups and arrays are used to dynamically change the shaders
312      based on preprocessor-like statements within the shaders.  These need
313      string lookups. */
314 
315 private:
316   // filename -> processed shader source, for #include preprocessor
317   std::map<std::string, std::string> shader_cache_processed;
318 
319   // variable -> boolean value for #ifdef preprocessor
320   std::map<std::string, bool> preproc_vars;
321 
322   std::unordered_map<size_t, gpuBuffer_t*> _gpu_object_map;
323   std::vector<size_t> _gpu_objects_to_free_vector;
324 public:
325   std::map<std::string, CShaderPrg*> programs;
326 
327   std::map<int, std::string> attribute_uids;
328   std::map<const std::string, int> attribute_uids_by_name;
329   int GetAttributeUID(const char * name);
330   const char *GetAttributeName(int);
331 
332   short print_warnings;
333   int reload_bits;
334   GLfloat line_width_range[2];
335   short stereo_flag; /* -1 left; 0 = off; 1 = right */
336   short stereo_blend;  /* 0 - no blend, 1 - blend  : for right eye stereo in full-screen e.g., anaglyph */
337   bool stereo_draw_buffer_pass;
338   GLint default_framebuffer_id { 0 };
339 private:
340   bool is_configured { false };
341 public:
IsConfigured()342   bool IsConfigured(){ return is_configured; }
343   // filename -> used by shader
344   std::map<std::string, std::vector<std::string> > shader_deps;
345 
346   // Post process render targets
347   std::size_t offscreen_rt { 0 }; //Texture before postprocessing;
348 #ifndef _PYMOL_NO_AA_SHADERS
349   std::unique_ptr<PostProcess> smaa_pp;
350 #endif
351   std::unique_ptr<PostProcess> oit_pp;
352 
353   void bindOffscreen(int width, int height, GridInfo * grid);
354   void bindOffscreenOIT(int width, int height, int drawbuf = 0);
355 
356   /**
357    * Activates/Binds offscreen render target.
358    * @param textureIdx offset of texture unit to assign (0 for GL_TEXTURE0, 1
359    * for GL_TEXTURE1, etc...)
360    * @Note: indices should preferably be passed in as enum or named variable for
361    * clarity
362    */
363   void activateOffscreenTexture(GLuint textureIdx);
364 };
365 
366 bool ShaderMgrInit(PyMOLGlobals * G);
367 
368 /* for reload_bits */
369 enum {
370   RELOAD_VARIABLES              = 0x01,
371   RELOAD_CALLCOMPUTELIGHTING    = 0x02,
372   RELOAD_ALL_SHADERS            = 0xff,
373 };
374 
375 #define VERTEX_POS_SIZE    3
376 #define VERTEX_COLOR_SIZE  4
377 
378 #define VERTEX_POS    0
379 #define VERTEX_NORMAL 1
380 #define VERTEX_COLOR  2
381 
382 #define CYLINDER_VERTEX1 0
383 #define CYLINDER_VERTEX2 1
384 #define CYLINDER_COLOR   2
385 #define CYLINDER_COLOR2  3
386 #define CYLINDER_RADIUS  4
387 #define CYLINDER_CAP     5
388 
389 #define RAMP_OFFSETPT 0
390 
391 #endif
392 
393 // vi:sw=2:expandtab
394