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
17 #include "os_gl.h"
18 #include "os_python.h"
19 #include <string.h>
20 #include <iostream>
21 #include "ShaderMgr.h"
22 #include "OOMac.h"
23 #include "ListMacros.h"
24 #include "PyMOLOptions.h"
25 #include "Feedback.h"
26 #include "MemoryDebug.h"
27 #include "Setting.h"
28 #include "Scene.h"
29 #include "Color.h"
30 #include "Vector.h"
31 #include "Util.h"
32 #include "Util2.h"
33 #include "Texture.h"
34 #include "FileStream.h"
35 #include "Matrix.h"
36 #include "Parse.h"
37
38 #ifndef _PYMOL_NO_AA_SHADERS
39 #endif
40
41 #include "CGO.h"
42 #ifdef _WEBGL
43 #include "Matrix.h"
44 #include "WebPyMOLLibrary.h"
45 #endif
46 #define MAX_LOG_LEN 1024
47
48 #include <algorithm>
49 #include <sstream>
50 #include <stack>
51 #include <vector>
52 #include <functional>
53 /* Texture Usage:
54
55 0 - for not-PURE_OPENGL_ES_2: ObjectVolume: volumeTex
56 for WEBGL: SCHRODINGER logo
57 1 - for not-PURE_OPENGL_ES_2: Volume: either colorTex1D or colorTex2D
58 for _PYMOL_PRECOMPUTED_LIGHTING: Lighting Texture (ShaderMgr->lightingTexture)
59 2 - FXAA - color_texture
60 SMAA1 - colorTex
61 SMAA3 - colorTex
62 3 - SMAA3 - blendTex
63 Label/Indicator Shader : textureMap (both PURE_OPENGL_ES_2 and non-PURE_OPENGL_ES_2
64 4 - Background Texture: bgTextureMap
65 5 - OIT - 2nd pass : accumTex
66 Volumes - carvemask
67 6 - OIT - 2nd pass : revealageTex
68 SMAA2 - edgesTex
69 7 - SMAA2 - areaTex
70 OIT Copy - colorTex
71 8 - SMAA2 - searchTex
72
73 */
74
75 using namespace std;
76
77 #ifndef _DEAD_CODE_DIE
78 #define SUPPRESS_GEOMETRY_SHADER_ERRORS
79 #endif
80
81 #define CONNECTOR_GS_NUM_VERTICES 31
82
83 #define SCENEGETIMAGESIZE SceneGetWidthHeight
84
85 #include "ShaderText.h"
86
87 #define WARNING_IF_GLERROR(msg) { \
88 GLenum err; \
89 if ((err = glGetError())){ \
90 PRINTFB(G, FB_ShaderMgr, FB_Warnings) "GLERROR 0x%04x: %s\n", err, msg ENDFB(G); \
91 } \
92 }
93
glShaderSource1String(GLuint shad,const string & strobj)94 static void glShaderSource1String(GLuint shad, const string &strobj){
95 const GLchar *str = (const GLchar *)strobj.c_str();
96 glShaderSource(shad, 1, (const GLchar **)&str, nullptr);
97 }
98
reload()99 bool CShaderPrg::reload(){
100 // skip programs with empty file names, assume their code is managed
101 // outside of the reload logic (like ARB shaders).
102 if (is_valid || vertfile.empty())
103 return true;
104
105 string gs, vs, fs;
106 CShaderMgr *I = G->ShaderMgr;
107 GLint status;
108
109 if (!geomfile.empty())
110 gs = I->GetShaderSource(geomfile);
111
112 vs = I->GetShaderSource(vertfile);
113 fs = I->GetShaderSource(fragfile);
114
115 WARNING_IF_GLERROR("CShaderPrg::reload begin");
116
117 PRINTFB(G, FB_ShaderMgr, FB_Blather)
118 "Loading shader named: %s\n", name.c_str()
119 ENDFB(G);
120
121 if (!id) {
122 id = glCreateProgram();
123 }
124
125 #ifndef PURE_OPENGL_ES_2
126 if (!gs.empty() && SettingGetGlobal_b(G, cSetting_use_geometry_shaders)) {
127 if (!gid) {
128 gid = glCreateShader(GL_GEOMETRY_SHADER);
129
130 GLenum err;
131 if ((err=glGetError()) || !gid) {
132 PRINTFB(G, FB_ShaderMgr, FB_Errors)
133 " Error: geometry shader creation failed. name=%s err=0x%x\n", name.c_str(), err ENDFB(G);
134 return false;
135 }
136
137 glAttachShader(id, gid);
138 }
139
140 glShaderSource1String(gid, gs);
141 glCompileShader((GLuint) gid);
142 glGetShaderiv(gid, GL_COMPILE_STATUS, &status);
143
144 if (!status) {
145 #ifndef SUPPRESS_GEOMETRY_SHADER_ERRORS
146 ErrorMsgWithShaderInfoLog(gid, "geometry shader compilation failed.");
147 #endif
148 glDetachShader(id, gid);
149 glDeleteShader(gid);
150 gid = 0;
151 return false;
152 }
153
154 glProgramParameteriEXT(id, GL_GEOMETRY_INPUT_TYPE_EXT, gsInput);
155 glProgramParameteriEXT(id, GL_GEOMETRY_OUTPUT_TYPE_EXT, gsOutput);
156 glProgramParameteriEXT(id, GL_GEOMETRY_VERTICES_OUT_EXT, ngsVertsOut);
157
158 PRINTFB(G, FB_ShaderMgr, FB_Debugging)
159 " ShaderPrg-Debug: geometry shader compiled.\n" ENDFB(G);
160 } else if (gid) {
161 // for manually switching off geometry shaders (set use_geometry_shaders, off)
162 glDetachShader(id, gid);
163 glDeleteShader(gid);
164 gid = 0;
165 }
166
167 WARNING_IF_GLERROR("CShaderPrg::reload after geometry shader");
168 #endif
169
170 // vertex shader
171 {
172 if (!vid) {
173 vid = glCreateShader(GL_VERTEX_SHADER);
174 glAttachShader(id, vid);
175 }
176
177 glShaderSource1String(vid, vs);
178 glCompileShader((GLuint) vid);
179 glGetShaderiv(vid, GL_COMPILE_STATUS, &status);
180
181 if (!status) {
182 ErrorMsgWithShaderInfoLog(vid, "vertex shader compilation failed.");
183 return false;
184 }
185 }
186
187 // fragment shader
188 {
189 if (!fid) {
190 fid = glCreateShader(GL_FRAGMENT_SHADER);
191 glAttachShader(id, fid);
192 }
193
194 glShaderSource1String(fid, fs);
195 glCompileShader((GLuint) fid);
196 glGetShaderiv(fid, GL_COMPILE_STATUS, &status);
197
198 if (!status) {
199 ErrorMsgWithShaderInfoLog(fid, "fragment shader compilation failed.");
200 return false;
201 }
202 }
203
204 uniforms.clear();
205 uniform_set = 0;
206
207 // it is valid to bind unused names, and to bind multiple names to the same index
208 if (!name.compare(0, 8, "cylinder")){
209 glBindAttribLocation(id, CYLINDER_VERTEX1, "attr_vertex1");
210 glBindAttribLocation(id, CYLINDER_VERTEX2, "attr_vertex2");
211 glBindAttribLocation(id, CYLINDER_COLOR, "a_Color");
212 glBindAttribLocation(id, CYLINDER_COLOR2, "a_Color2");
213 glBindAttribLocation(id, CYLINDER_RADIUS, "attr_radius");
214 glBindAttribLocation(id, CYLINDER_CAP, "a_cap");
215 } else {
216 glBindAttribLocation(id, VERTEX_POS, "a_Vertex");
217 glBindAttribLocation(id, VERTEX_COLOR, "a_Color");
218 glBindAttribLocation(id, VERTEX_NORMAL, "a_Normal");
219 glBindAttribLocation(id, 0, "attr_worldpos");
220 }
221 WARNING_IF_GLERROR("after glBindAttribLocation");
222
223 is_linked = false;
224 is_valid = true;
225
226 return true;
227 }
228
229 #define MASK_SHADERS_PRESENT_GEOMETRY 0x2;
230 #define MASK_SHADERS_PRESENT_SMAA 0x4;
231
232 static void getGLVersion(PyMOLGlobals * G, int *major, int* minor);
233 static void getGLSLVersion(PyMOLGlobals * G, int* major, int* minor);
234
235 static void disableShaders(PyMOLGlobals * G);
236
237 #ifdef WIN32
238 /* REMOVE US */
getTexImage3D()239 PFNGLTEXIMAGE3DPROC getTexImage3D(){
240 static PFNGLTEXIMAGE3DPROC my_glTexImage3D = NULL;
241 if (!my_glTexImage3D)
242 my_glTexImage3D = (PFNGLTEXIMAGE3DPROC) wglGetProcAddress("glTexImage3D");
243 return my_glTexImage3D;
244 }
245 #endif
246
247 /*
248 * Use this to turn off shaders if the renderer cannot use them.
249 */
disableShaders(PyMOLGlobals * G)250 void disableShaders(PyMOLGlobals * G) {
251 /* Auto-disable shader-based rendering */
252 SettingSetGlobal_b(G, cSetting_use_shaders, false);
253 }
254
disableGeometryShaders(PyMOLGlobals * G)255 static void disableGeometryShaders(PyMOLGlobals * G) {
256 SettingSetGlobal_b(G, cSetting_use_geometry_shaders, false);
257 if(G->ShaderMgr)
258 G->ShaderMgr->SetPreprocVar("use_geometry_shaders", false);
259
260 if (G->Option && !G->Option->quiet)
261 PRINTFB(G, FB_ShaderMgr, FB_Warnings)
262 " Geometry shaders not available\n" ENDFB(G);
263 }
264
265 /*
266 * Replace strings from a list of pairs.
267 *
268 * src: string to modify
269 * replaceStrings: map of strings to replace (as consecutive elements in an
270 * array like {from1, to1, from2, to2, ..., ""}
271 * returns: new string
272 */
stringReplaceAll(const string & src,const string * replaceStrings)273 static string stringReplaceAll(const string &src, const string * replaceStrings) {
274 string dest = src;
275 for (int i = 0; !replaceStrings[i].empty(); i += 2) {
276 int slen1 = replaceStrings[i].length();
277 int slen2 = replaceStrings[i + 1].length();
278 for (size_t pl = 0;
279 (pl = dest.find(replaceStrings[i], pl)) != string::npos;
280 pl += slen2) {
281 dest.replace(pl, slen1, replaceStrings[i + 1]);
282 }
283 }
284 return dest;
285 }
286
287 /*
288 * Reload "CallComputeColorForLight" shader replacement string
289 */
Reload_CallComputeColorForLight()290 void CShaderMgr::Reload_CallComputeColorForLight(){
291 if ((reload_bits & RELOAD_CALLCOMPUTELIGHTING)) {
292 reload_bits &= ~RELOAD_CALLCOMPUTELIGHTING;
293 } else {
294 return;
295 }
296
297 if (SettingGetGlobal_b(G, cSetting_precomputed_lighting)) {
298 Generate_LightingTexture();
299 return;
300 }
301
302 int light_count = SettingGetGlobal_i(G, cSetting_light_count);
303 int spec_count = SettingGetGlobal_i(G, cSetting_spec_count);
304 ostringstream accstr;
305
306 string rawtemplate = GetShaderSource("call_compute_color_for_light.fs");
307
308 string lightstrings[] = {
309 "`light`", "0",
310 "`postfix`", "_0",
311 ""
312 };
313
314 accstr << stringReplaceAll(rawtemplate, lightstrings);
315
316 if (light_count > 8){
317 PRINTFB(G, FB_ShaderMgr, FB_Details)
318 " ShaderMgr-Detail: using 8 lights (use precomputed_lighting for light_count > 8)\n"
319 ENDFB(G);
320 light_count = 8;
321 }
322
323 // no postfix for 1..light_count
324 lightstrings[3] = "";
325
326 for (int i=1; i<light_count; i++){
327 ostringstream lstr;
328 lstr << i;
329 lightstrings[1] = lstr.str(); // std::to_string(i)
330
331 if (i == spec_count + 1) {
332 // no specular for [spec_count + 1 .. light_count]
333 lightstrings[3] = " * 0.0";
334 }
335
336 accstr << stringReplaceAll(rawtemplate, lightstrings);
337 }
338
339 SetShaderSource("CallComputeColorForLight", accstr.str());
340 }
341
Invalidate_All_Shaders()342 void CShaderMgr::Invalidate_All_Shaders(){
343 for (auto& prog : programs) {
344 prog.second->Invalidate();
345 }
346 }
347
Reload_All_Shaders()348 void CShaderMgr::Reload_All_Shaders(){
349 Reload_Shader_Variables();
350 Reload_CallComputeColorForLight();
351
352 if (SettingGetGlobal_i(G, cSetting_transparency_mode) == 3) {
353 Reload_Derivatives("NO_ORDER_TRANSP");
354 }
355
356 for (auto& prog : programs) {
357 if (prog.second->derivative.empty())
358 prog.second->reload();
359 }
360 }
361
362 // bitmasks for preprocessor parsing
363 #define IFDEF 1 // #ifdef or #ifndef
364 #define IFNDEF 2 // #ifndef
365 #define ELSE 4 // #else
366 #define ENDIF 8 // #endif
367 #define INCLUDE 16 // #include
368 #define LOOKUP 32 // #ifdef or #ifndef or #include
369
370 // preprocessor directive (like '#ifdef') -> bitmask
371 static map<string, short> preprocmap;
372
373 // filename -> contents (static filesystem)
374 static map<string, const char *> shader_cache_raw;
375
376 // preproc variable -> NULL terminated list of filenames ("used by")
377 std::map<std::string, const char **> ifdef_deps;
378
379 // filename -> NULL terminated list of filenames ("included by")
380 std::map<std::string, const char **> include_deps;
381
382 /*
383 * Return a pointer to the next whitespace character or to the end of the string
384 */
nextwhitespace(const char * p)385 static const char * nextwhitespace(const char * p) {
386 for (;; p++) {
387 switch (*p) {
388 case ' ': case '\0': case '\n': case '\r': case '\t':
389 return p;
390 }
391 }
392 }
393
394 /*
395 * Return a pointer to the next line beginning or to the end of the string.
396 * Skips blank lines.
397 */
nextline(const char * p)398 static const char * nextline(const char * p) {
399 for (;; p++) {
400 switch (*p) {
401 case '\0': case '\n': case '\r':
402 goto switch2;
403 }
404 }
405 for (;; p++) {
406 switch2:
407 switch (*p) {
408 case ' ': case '\n': case '\r': case '\t':
409 break;
410 default:
411 return p;
412 }
413 }
414 }
415
416 /*
417 * Get the processed shader file contents with all #ifdef and #include
418 * preprocessors processed.
419 *
420 * Note: There must be a single whitespace character between preprocessor
421 * directive and argument.
422 *
423 * Valid:
424 * #ifdef foo
425 *
426 * Invalid:
427 * # ifdef foo
428 * #ifdef foo
429 *
430 * Function arguments:
431 * filename: file name of the shader file inside $PYMOL_DATA/shaders
432 */
GetShaderSource(const string & filename)433 string CShaderMgr::GetShaderSource(const string &filename)
434 {
435 // processed cache
436 auto it = shader_cache_processed.find(filename);
437 if (it != shader_cache_processed.end()) {
438 return it->second;
439 }
440
441 std::string buffer;
442 const char *pl = nullptr, *newpl, *tpl;
443 std::ostringstream newbuffer;
444
445 /* "if_depth" counts the level of nesting, and "true_depth" how far the
446 * if conditions were actually true. So if the current block is true, then
447 * if_depth == true_depth, otherwise if_depth > true_depth.
448 */
449 int if_depth = 0, true_depth = 0;
450
451 #ifndef _PYMOL_IOS
452 /* read the file from disk */
453 if (SettingGetGlobal_b(G, cSetting_shaders_from_disk)) {
454 const char * pymol_data = getenv("PYMOL_DATA");
455
456 if (pymol_data && pymol_data[0]) {
457 string path(pymol_data);
458 path.append(PATH_SEP).append("shaders").append(PATH_SEP).append(filename);
459
460 try {
461 buffer = pymol::file_get_contents(path);
462 pl = buffer.c_str();
463 } catch (...) {
464 PRINTFB(G, FB_ShaderMgr, FB_Warnings)
465 " Warning: shaders_from_dist=on, but unable to open file '%s'\n",
466 path.c_str() ENDFB(G);
467 }
468 } else {
469 PRINTFB(G, FB_ShaderMgr, FB_Warnings)
470 " Warning: shaders_from_dist=on, but PYMOL_DATA not set\n" ENDFB(G);
471 }
472 }
473 #endif
474
475 if (!pl) {
476 pl = shader_cache_raw[filename];
477 if (!pl) {
478 PRINTFB(G, FB_ShaderMgr, FB_Errors)
479 " GetShaderSource-Error: No such file: '%s'\n", filename.c_str() ENDFB(G);
480 return "";
481 }
482 }
483
484 /* Now we need to read through the shader and do processing if necessary */
485 for (; *pl; pl = newpl) {
486 int preproc = 0;
487
488 // only do preprocessor lookup if line starts with a hash
489 if (pl[0] == '#') {
490 // next white space
491 tpl = nextwhitespace(pl);
492
493 // copy of first word
494 string tmp_str(pl, tpl - pl);
495
496 // lookup word in preprocmap
497 map<string, short>::const_iterator
498 preprocit = preprocmap.find(tmp_str);
499 if (preprocit != preprocmap.end()) {
500 preproc = preprocit->second;
501
502 if (preproc & LOOKUP) { // #ifdef or #ifndef or #include
503 if (if_depth == true_depth) {
504 // copy of second word
505 tpl++;
506 tmp_str = string(tpl, nextwhitespace(tpl) - tpl);
507
508 if (preproc & IFDEF) { // #ifdef or #ifndef
509 bool if_value = false;
510
511 // lookup for boolean shader preprocessor values
512 auto item = preproc_vars.find(tmp_str);
513 if (item != preproc_vars.end())
514 if_value = item->second;
515
516 if (preproc & IFNDEF)
517 if_value = !if_value; // #ifndef
518
519 if (if_value)
520 true_depth++;
521
522 } else if (preproc & INCLUDE) { //#include
523 tmp_str = string(tpl, nextwhitespace(tpl) - tpl);
524 newbuffer << GetShaderSource(tmp_str);
525 }
526 }
527
528 if (preproc & IFDEF)
529 if_depth++;
530
531 } else if (preproc & ENDIF){ // #endif
532 if (if_depth-- == true_depth)
533 true_depth--;
534 } else if (preproc & ELSE){ // #else
535 if (if_depth == true_depth)
536 true_depth--;
537 else if (if_depth == true_depth + 1)
538 true_depth++;
539 }
540 }
541 }
542
543 newpl = nextline(pl);
544
545 // add to the output buffer if this is a regular active line
546 if (!preproc && if_depth == true_depth) {
547 newbuffer.write(pl, newpl - pl);
548 }
549 }
550
551 string result = newbuffer.str();
552 shader_cache_processed[filename] = result;
553 return result;
554 }
555
556 #define FREE_AND_REPLACE_WITH(var, with) if (var) free(var); var = with;
557
Reload_Shader_Variables()558 void CShaderMgr::Reload_Shader_Variables() {
559 if ((reload_bits & RELOAD_VARIABLES)) {
560 reload_bits &= ~RELOAD_VARIABLES;
561 } else {
562 return;
563 }
564
565 int bg_image_mode = SettingGetGlobal_i(G, cSetting_bg_image_mode);
566 int bg_gradient = SettingGetGlobal_b(G, cSetting_bg_gradient);
567 int bg_image_mode_solid;
568 int stereo, stereo_mode;
569 const char * bg_image_filename = SettingGet_s(G, nullptr, nullptr, cSetting_bg_image_filename);
570 short bg_image = bg_image_filename && bg_image_filename[0];
571 bg_image_mode_solid = !(bg_gradient || bg_image || OrthoBackgroundDataIsSet(*G->Ortho));
572
573 SetPreprocVar("bg_image_mode_solid", bg_image_mode_solid);
574 if (!bg_image_mode_solid) {
575 SetPreprocVar("bg_image_mode_1_or_3", (bg_image_mode == 1 || bg_image_mode == 3));
576 SetPreprocVar("bg_image_mode_2_or_3", (bg_image_mode == 2 || bg_image_mode == 3));
577 }
578
579 #ifndef PYMOL_EDU
580 SetPreprocVar("volume_mode", SettingGetGlobal_i(G, cSetting_volume_mode));
581 #endif
582
583 SetPreprocVar("ortho", SettingGetGlobal_i(G, cSetting_ortho));
584 SetPreprocVar("depth_cue", SettingGetGlobal_b(G, cSetting_depth_cue)
585 && SettingGetGlobal_b(G, cSetting_fog) != 0.0F);
586
587 #ifndef PURE_OPENGL_ES_2
588 SetPreprocVar("use_geometry_shaders", SettingGetGlobal_b(G, cSetting_use_geometry_shaders));
589 #endif
590
591 SetPreprocVar("line_smooth", SettingGetGlobal_b(G, cSetting_line_smooth));
592
593 stereo = SettingGetGlobal_i(G, cSetting_stereo);
594 stereo_mode = SettingGetGlobal_i(G, cSetting_stereo_mode);
595
596 #ifdef _PYMOL_OPENVR
597 SetPreprocVar("openvr_enabled", stereo && stereo_mode == cStereo_openvr);
598 #endif
599
600 SetPreprocVar("ANAGLYPH", stereo && stereo_mode == cStereo_anaglyph);
601 SetPreprocVar("ray_trace_mode_3", SettingGetGlobal_i(G, cSetting_ray_trace_mode) == 3);
602 SetPreprocVar("transparency_mode_3", SettingGetGlobal_i(G, cSetting_transparency_mode)==3);
603
604 #ifndef _PYMOL_NO_AA_SHADERS
605 #endif
606
607 SetPreprocVar("precomputed_lighting", SettingGetGlobal_b(G, cSetting_precomputed_lighting));
608 SetPreprocVar("ray_transparency_oblique", SettingGetGlobal_f(G, cSetting_ray_transparency_oblique) > R_SMALL4);
609
610 int chromadepth = SettingGetGlobal_i(G, cSetting_chromadepth);
611 SetPreprocVar("chromadepth", chromadepth != 0);
612 SetPreprocVar("chromadepth_postlighting", chromadepth == 2);
613 }
614
615 /* ============================================================================
616 * ShaderMgrInit is called from PyMOL.c during start up; it just allocates
617 * the global ShaderMgr
618 */
ShaderMgrInit(PyMOLGlobals * G)619 bool ShaderMgrInit(PyMOLGlobals * G) {
620 // initialize some globals (do this only once)
621 if (preprocmap.empty()) {
622 preprocmap["#ifdef"] = LOOKUP | IFDEF;
623 preprocmap["#ifndef"] = LOOKUP | IFDEF | IFNDEF;
624 preprocmap["#else"] = ELSE;
625 preprocmap["#endif"] = ENDIF;
626 preprocmap["#include"] = LOOKUP | INCLUDE;
627
628 // make #include dependency map from flat array
629 for (const char ** ptr = _include_deps; *ptr; ++ptr) {
630 include_deps[ptr[0]] = ptr + 1;
631 while (*(++ptr)) {}
632 }
633
634 // make #ifdef dependency map from flat array
635 for (const char ** ptr = _ifdef_deps; *ptr; ++ptr) {
636 ifdef_deps[ptr[0]] = ptr + 1;
637 while (*(++ptr)) {}
638 }
639
640 // make shader file cache from flat array
641 for (const char ** ptr = _shader_cache_raw; *ptr; ptr += 2) {
642 shader_cache_raw[ptr[0]] = *(ptr + 1);
643 }
644 }
645
646 G->ShaderMgr = new CShaderMgr(G);
647
648 if(!G->ShaderMgr)
649 return false;
650
651 return true;
652 }
653
654 /*
655 * Print the given message as ShaderMgr-Error, followed by the shader info log.
656 */
ErrorMsgWithShaderInfoLog(const GLuint sid,const char * msg)657 void CShaderPrg::ErrorMsgWithShaderInfoLog(const GLuint sid, const char * msg) {
658 if (!G->Option || G->Option->quiet)
659 return;
660
661 GLint infoLogLength = 0;
662 glGetShaderiv(sid, GL_INFO_LOG_LENGTH, &infoLogLength);
663 vector<GLchar> infoLog(infoLogLength);
664 glGetShaderInfoLog(sid, infoLogLength, nullptr, infoLog.data());
665
666 PRINTFB(G, FB_ShaderPrg, FB_Errors) " ShaderPrg-Error: %s; name='%s'\n",
667 msg, name.c_str() ENDFB(G);
668
669 PRINTFB(G, FB_ShaderPrg, FB_Errors) " ShaderPrg-Error-InfoLog:\n%s\n",
670 infoLog.data() ENDFB(G);
671 }
672
673 /* ShaderMgrConfig -- Called from PyMOL.c, configures the global ShaderMgr
674 * This needs to be called once the OpenGL context has been created, it is
675 * called from MainInit() for PyMol, and from PyMOL_ConfigureShadersGL() for
676 * other programs (i.e., JyMOL, AxPyMOL, etc.).
677 */
Config()678 void CShaderMgr::Config() {
679 if (!G || !G->HaveGUI) /* && G->ValidContext); */
680 return;
681
682 glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, line_width_range);
683
684 #ifndef PURE_OPENGL_ES_2
685 GLenum err = glewInit();
686
687 if (GLEW_OK==err) {
688 GLint gl_major = 0, gl_minor = 0;
689 getGLVersion(G, &gl_major, &gl_minor);
690
691 PRINTFB(G, FB_ShaderMgr, FB_Details)
692 " Detected OpenGL version %d.%d.", gl_major, gl_minor ENDFB(G);
693
694 if (GLEW_VERSION_2_0) {
695 G->Feedback->add(" Shaders available.\n");
696 }
697 else {
698 G->Feedback->add(" Shaders and volumes unavailable.\n");
699 disableShaders(G);
700 return;
701 }
702 }
703 else {
704 /* print info on glew error? */
705 G->Feedback->add(" There was an error intializing GLEW. Basic graphics, including\n shaders and volumes may be unavailable.\n");
706 disableShaders(G);
707 fprintf(stderr, " GLEW-Error: %s\n", glewGetErrorString(err));
708 return;
709 }
710 #endif
711
712 // static preprocessor values
713 preproc_vars["GLEW_VERSION_3_0"] = GLEW_VERSION_3_0 ? true : false;
714 if (TM3_IS_ONEBUF){
715 preproc_vars["ONE_DRAW_BUFFER"] = true;
716 }
717 #ifdef PURE_OPENGL_ES_2
718 preproc_vars["PURE_OPENGL_ES_2"] = 1;
719 preproc_vars["PYMOL_WEBGL"] = 1;
720 preproc_vars["PYMOL_WEBGL_IOS"] = 1;
721 #else
722 preproc_vars["gl_VertexID_enabled"] = GLEW_EXT_gpu_shader4;
723 #endif
724
725 // shaders
726 #define make_program(name, ...) programs[name] = new CShaderPrg(G, name, __VA_ARGS__)
727
728 make_program("bg", "bg.vs", "bg.fs");
729 make_program("indicator", "indicator.vs", "indicator.fs");
730 make_program("label", "label.vs", "label.fs");
731
732 #ifndef PURE_OPENGL_ES_2
733 make_program("volume", "volume.vs", "volume.fs");
734 #endif
735
736 make_program("default", "default.vs", "default.fs");
737 make_program("surface", "surface.vs", "surface.fs");
738
739 make_program("line", "line.vs", "line.fs");
740
741 make_program("screen", "screen.vs", "screen.fs");
742
743 if (GLEW_EXT_geometry_shader4 && GLEW_EXT_gpu_shader4){
744 make_program("connector", "connector.vs", "connector.fs",
745 "connector.gs", GL_POINTS, GL_TRIANGLE_STRIP, CONNECTOR_GS_NUM_VERTICES);
746 } else {
747 make_program("connector", "connector.vs", "connector.fs");
748 }
749
750 if (GET_FRAGDEPTH_SUPPORT()) {
751 make_program("cylinder", "cylinder.vs", "cylinder.fs");
752 make_program("sphere", "sphere.vs", "sphere.fs");
753 }
754
755 make_program("ramp", "ramp.vs", "ramp.fs");
756 programs["ramp"]->uniformLocations[RAMP_OFFSETPT] = "offsetPt";
757
758 make_program("oit", "oit.vs", "oit.fs");
759 make_program("copy", "copy.vs", "copy.fs");
760 make_program("trilines", "trilines.vs", "trilines.fs");
761
762 Reload_Shader_Variables();
763 Reload_CallComputeColorForLight();
764
765 // shaders availability test
766 ok_assert(1, programs["default"]->reload());
767
768 #ifndef PURE_OPENGL_ES_2
769 // geometry shaders availability test
770 if (programs["connector"]->reload() && programs["connector"]->gid) {
771 shaders_present |= MASK_SHADERS_PRESENT_GEOMETRY;
772 } else {
773 disableGeometryShaders(G);
774 }
775 #else
776 SettingSetGlobal_b(G, cSetting_use_geometry_shaders, 0);
777 #endif
778
779 #define check_program(name, setting, value) { \
780 if (!programs[name]->reload()) { \
781 SettingSetGlobal_i(G, setting, value); \
782 programs.erase(name); \
783 }} \
784 // other shader compilation tests
785 if (GET_FRAGDEPTH_SUPPORT()) {
786 check_program("cylinder", cSetting_render_as_cylinders, 0);
787 check_program("sphere", cSetting_sphere_mode, 0);
788 }
789
790 #ifndef _PYMOL_NO_AA_SHADERS
791 #endif
792
793 // get filename -> shader program dependencies
794 for (auto& prog : programs) {
795 RegisterDependantFileNames(prog.second);
796 }
797
798 // make transparency_mode_3 shader derivatives
799 MakeDerivatives("_t", "NO_ORDER_TRANSP");
800
801 #ifndef PURE_OPENGL_ES_2
802 /* report GLSL version */
803 if (G && G->Option && !G->Option->quiet) {
804 char buf[50];
805 int major, minor;
806 getGLSLVersion(G, &major, &minor);
807 sprintf(buf, " Detected GLSL version %d.%d.\n", major, minor);
808 G->Feedback->add(buf);
809 }
810 #endif
811 shaders_present |= 0x1;
812 SettingSetGlobal_b(G, cSetting_use_shaders, true);
813
814 is_configured = true;
815 return;
816 ok_except1:
817 disableShaders(G);
818 G->ShaderMgr->shaders_present = 0;
819 is_configured = true;
820 }
821
822 /* getGLVersion -- determine user's GL version
823 * PARAMS
824 * major, return value for major
825 * minor, return value for minor
826 *
827 * RETURNS
828 * nothing; writes to major and minor
829 */
getGLVersion(PyMOLGlobals * G,int * major,int * minor)830 void getGLVersion(PyMOLGlobals * G, int *major, int* minor) {
831 /* query the version string */
832 const char* verstr = (const char*) glGetString(GL_VERSION);
833 /* attempt to store the values into major and minor */
834 if (!verstr || sscanf(verstr, "%d.%d", major, minor) != 2) {
835 *major = *minor = 0;
836 /* Use PyMOL FB system, instead of fprintf */
837 PRINTFD(G, FB_ObjectVolume)
838 "Invalid GL_VERSION format.\n" ENDFD;
839 }
840 }
841
842
843 /* getGLSLVersion -- determine user's GLSL version
844 * PARAMS
845 * major, rval for major
846 * minor, rval for minor
847 */
848 #ifndef PURE_OPENGL_ES_2
getGLSLVersion(PyMOLGlobals * G,int * major,int * minor)849 void getGLSLVersion(PyMOLGlobals * G, int* major, int* minor) {
850 int gl_major, gl_minor;
851 *major = *minor = 0;
852
853 /* grab the GL version */
854 getGLVersion(G, &gl_major, &gl_minor);
855
856 /* GL version 1 */
857 if (1==gl_major) {
858 const char* extstr = (const char*) glGetString(GL_EXTENSIONS);
859 if (extstr && strstr(extstr, "GL_ARB_shading_language_100")) {
860 *major = 1;
861 *minor = 0;
862 }
863 }
864 /* GL > version 1 */
865 else if (gl_major>=2) {
866 const char* verstr = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION);
867
868 if (!verstr || sscanf(verstr, "%d.%d", major, minor) != 2) {
869 *major = *minor = 0;
870
871 if (G && G->Option && !G->Option->quiet) {
872 PRINTFD(G, FB_ObjectVolume)
873 "Invalid GL_SHADING_LANGUAGE_VERSION format.\n" ENDFD;
874 }
875 }
876 }
877 }
878 #endif
879
880
881
882 /* ============================================================================
883 * CShaderMgr -- Simple Shader Manager class
884 */
CShaderMgr(PyMOLGlobals * G_)885 CShaderMgr::CShaderMgr(PyMOLGlobals * G_)
886 {
887 G = G_;
888 current_shader = nullptr;
889 shaders_present = 0;
890 stereo_flag = 0;
891 stereo_blend = 0;
892 #ifdef _PYMOL_LIB
893 print_warnings = 0;
894 #else
895 print_warnings = 1;
896 #endif
897
898 lightingTexture = 0;
899 is_picking = 0;
900 reload_bits = RELOAD_ALL_SHADERS;
901
902 #ifndef _WEBGL
903 vbos_to_free.reserve(256);
904 #endif
905 }
906
~CShaderMgr()907 CShaderMgr::~CShaderMgr() {
908 for (auto& prog : programs) {
909 delete prog.second;
910 }
911 programs.clear();
912
913 shader_cache_processed.clear();
914
915 freeGPUBuffer(offscreen_rt);
916
917 FreeAllVBOs();
918 }
919
AddShaderPrg(CShaderPrg * s)920 int CShaderMgr::AddShaderPrg(CShaderPrg * s) {
921 if (!s)
922 return 0;
923 const string& name = s->name;
924 if (programs.find(name)!=programs.end()){
925 delete programs[name];
926 }
927 programs[name] = s;
928 return 1;
929 }
930
RemoveShaderPrg(const string & name)931 int CShaderMgr::RemoveShaderPrg(const string& name) {
932 if (programs.find(name) != programs.end()){
933 delete programs[name];
934 }
935 return 1;
936 }
937
938 /*
939 * Lookup a shader program by name and set it as the `current_shader` of the
940 * shader manager. If `pass` is provided and is less than zero, and we are
941 * in transparency_mode 3, then look up the NO_ORDER_TRANSP derivative.h
942 */
GetShaderPrg(std::string name,short set_current_shader,short pass)943 CShaderPrg * CShaderMgr::GetShaderPrg(std::string name, short set_current_shader, short pass) {
944 if (pass < 0 && SettingGetGlobal_i(G, cSetting_transparency_mode) == 3) {
945 name += "_t";
946 }
947
948 auto it = programs.find(name);
949 if (it == programs.end())
950 return nullptr;
951
952 if (set_current_shader)
953 current_shader = it->second;
954
955 return it->second;
956 }
957
ShaderPrgExists(const char * name)958 int CShaderMgr::ShaderPrgExists(const char * name){
959 return (programs.find(name) != programs.end());
960 }
961
ShadersPresent()962 int CShaderMgr::ShadersPresent() {
963 return shaders_present;
964 }
965
GeometryShadersPresent()966 int CShaderMgr::GeometryShadersPresent() {
967 return shaders_present & MASK_SHADERS_PRESENT_GEOMETRY;
968 }
969
970 /*
971 * glDeleteBuffers for vbos_to_free
972 */
FreeAllVBOs()973 void CShaderMgr::FreeAllVBOs() {
974 #ifndef _WEBGL
975 freeAllGPUBuffers();
976
977 LOCK_GUARD_MUTEX(lock, vbos_to_free_mutex);
978
979 if (vbos_to_free.empty())
980 return;
981
982 glDeleteBuffers(vbos_to_free.size(), &vbos_to_free[0]);
983
984 vbos_to_free.clear();
985 #endif
986 }
987
AddVBOsToFree(GLuint * vboid,int nvbos)988 void CShaderMgr::AddVBOsToFree(GLuint *vboid, int nvbos){
989 int i;
990 for (i=0; i<nvbos; i++){
991 if (vboid[i]>0)
992 AddVBOToFree(vboid[i]);
993 }
994 }
995
996 /*
997 * thread-safe deferred glDeleteBuffers(1, &vboid)
998 */
AddVBOToFree(GLuint vboid)999 void CShaderMgr::AddVBOToFree(GLuint vboid){
1000 #ifdef _WEBGL // No threads, immediately delete
1001 if (glIsBuffer(vboid)) {
1002 glDeleteBuffers(1, &vboid);
1003 } else {
1004 PRINTFB(G, FB_ShaderMgr, FB_Warnings) "WARNING: CShaderMgr_AddVBOToFree() buffer is not a VBO %d", vboid ENDFB(G);
1005 }
1006 #else
1007 LOCK_GUARD_MUTEX(lock, vbos_to_free_mutex);
1008 vbos_to_free.push_back(vboid);
1009 #endif
1010 }
1011
Enable_DefaultShaderWithSettings(const CSetting * set1,const CSetting * set2,int pass)1012 CShaderPrg *CShaderMgr::Enable_DefaultShaderWithSettings(
1013 const CSetting *set1,
1014 const CSetting *set2, int pass) {
1015 CShaderPrg * shaderPrg = Get_DefaultShader(pass);
1016 return Setup_DefaultShader(shaderPrg, set1, set2);
1017 }
1018
Enable_DefaultShader(int pass)1019 CShaderPrg *CShaderMgr::Enable_DefaultShader(int pass){
1020 CShaderPrg * shaderPrg = Get_DefaultShader(pass);
1021 return Setup_DefaultShader(shaderPrg, nullptr, nullptr);
1022 }
1023
Enable_LineShader(int pass)1024 CShaderPrg *CShaderMgr::Enable_LineShader(int pass){
1025 CShaderPrg * shaderPrg = Get_LineShader(pass);
1026 return Setup_DefaultShader(shaderPrg, nullptr, nullptr);
1027 }
1028
Enable_SurfaceShader(int pass)1029 CShaderPrg *CShaderMgr::Enable_SurfaceShader(int pass){
1030 CShaderPrg * shaderPrg = Get_SurfaceShader(pass);
1031 return Setup_DefaultShader(shaderPrg, nullptr, nullptr);
1032 }
1033
Enable_ConnectorShader(int pass)1034 CShaderPrg *CShaderMgr::Enable_ConnectorShader(int pass){
1035 CShaderPrg * shaderPrg = Get_ConnectorShader(pass);
1036 if (!shaderPrg)
1037 return nullptr;
1038 shaderPrg = Setup_DefaultShader(shaderPrg, nullptr, nullptr);
1039 shaderPrg->SetLightingEnabled(0);
1040 {
1041 float front, back;
1042 front = SceneGetCurrentFrontSafe(G);
1043 back = SceneGetCurrentBackSafe(G);
1044 shaderPrg->Set1f("front", front);
1045 shaderPrg->Set1f("clipRange", back - front);
1046 }
1047
1048 int width, height;
1049 SceneGetWidthHeightStereo(G, &width, &height);
1050 shaderPrg->Set2f("screenSize", width, height);
1051
1052 {
1053 float v_scale = SceneGetScreenVertexScale(G, nullptr);
1054 shaderPrg->Set1f("screenOriginVertexScale", v_scale/2.f);
1055 }
1056
1057 return shaderPrg;
1058 }
1059
Setup_DefaultShader(CShaderPrg * shaderPrg,const CSetting * set1,const CSetting * set2)1060 CShaderPrg *CShaderMgr::Setup_DefaultShader(CShaderPrg * shaderPrg,
1061 const CSetting *set1,
1062 const CSetting *set2) {
1063 if (!shaderPrg){
1064 current_shader = nullptr;
1065 return shaderPrg;
1066 }
1067 shaderPrg->Enable();
1068 shaderPrg->SetBgUniforms();
1069 shaderPrg->Set_Stereo_And_AnaglyphMode();
1070
1071 bool two_sided_lighting_enabled = SceneGetTwoSidedLightingSettings(G, set1, set2);
1072
1073 shaderPrg->SetLightingEnabled(1); // lighting on by default
1074 shaderPrg->Set1i("two_sided_lighting_enabled", two_sided_lighting_enabled);
1075 shaderPrg->Set1f("ambient_occlusion_scale", 0.f);
1076 shaderPrg->Set1i("accessibility_mode", SettingGetGlobal_i(G, cSetting_ambient_occlusion_mode) / 4);
1077 shaderPrg->Set1f("accessibility_mode_on", SettingGetGlobal_i(G, cSetting_ambient_occlusion_mode) ? 1.f : 0.f);
1078
1079 // interior_color
1080 {
1081 int interior_color = SettingGet_i(G, set1, set2, cSetting_ray_interior_color);
1082 if (interior_color == cColorDefault || two_sided_lighting_enabled) {
1083 shaderPrg->Set1i("use_interior_color", 0);
1084 } else {
1085 float inter[] = { 0.f, 0.f, 0.f };
1086 ColorGetEncoded(G, interior_color, inter);
1087 shaderPrg->Set1i("use_interior_color", 1);
1088 shaderPrg->Set4f("interior_color", inter[0], inter[1], inter[2], 1.f);
1089 }
1090 }
1091
1092 shaderPrg->Set_Specular_Values();
1093 shaderPrg->Set_Matrices();
1094 return (shaderPrg);
1095 }
Enable_CylinderShader(int pass)1096 CShaderPrg *CShaderMgr::Enable_CylinderShader(int pass){
1097 return Enable_CylinderShader("cylinder", pass);
1098 }
1099
Enable_CylinderShader(const char * shader_name,int pass)1100 CShaderPrg *CShaderMgr::Enable_CylinderShader(const char *shader_name, int pass){
1101 int width, height;
1102 CShaderPrg *shaderPrg;
1103
1104 SceneGetWidthHeightStereo(G, &width, &height);
1105 shaderPrg = GetShaderPrg(shader_name, 1, pass);
1106 if (!shaderPrg)
1107 return nullptr;
1108 shaderPrg->Enable();
1109
1110 shaderPrg->SetLightingEnabled(1); // lighting on by default
1111
1112 shaderPrg->Set1f("uni_radius", 0.f);
1113
1114 shaderPrg->Set_Stereo_And_AnaglyphMode();
1115
1116 shaderPrg->Set1f("inv_height", 1.0/height);
1117 shaderPrg->Set1i("no_flat_caps", 1);
1118 {
1119 float smooth_half_bonds = (SettingGetGlobal_i(G, cSetting_smooth_half_bonds)) ? .2f : 0.f;
1120 shaderPrg->Set1f("half_bond", smooth_half_bonds);
1121 }
1122 shaderPrg->Set_Specular_Values();
1123 shaderPrg->Set_Matrices();
1124
1125 shaderPrg->SetBgUniforms();
1126
1127 // always enable backface culling for cylinders
1128 glCullFace(GL_BACK);
1129 glEnable(GL_CULL_FACE);
1130 return shaderPrg;
1131 }
1132
Get_DefaultSphereShader(int pass)1133 CShaderPrg *CShaderMgr::Get_DefaultSphereShader(int pass){
1134 return GetShaderPrg("sphere", 1, pass);
1135 }
1136
1137
Enable_DefaultSphereShader(int pass)1138 CShaderPrg *CShaderMgr::Enable_DefaultSphereShader(int pass) {
1139 CShaderPrg *shaderPrg = Get_DefaultSphereShader(pass);
1140 if (!shaderPrg) return nullptr;
1141 shaderPrg->Enable();
1142 shaderPrg->SetLightingEnabled(1);
1143 shaderPrg->Set1f("sphere_size_scale", 1.f);
1144
1145 shaderPrg->Set_Stereo_And_AnaglyphMode();
1146
1147 shaderPrg->Set_Specular_Values();
1148 shaderPrg->Set_Matrices();
1149
1150 shaderPrg->SetBgUniforms();
1151
1152 return (shaderPrg);
1153 }
1154
1155 #ifdef _PYMOL_ARB_SHADERS
Enable_SphereShaderARB()1156 CShaderPrg *CShaderMgr::Enable_SphereShaderARB(){
1157 CShaderPrg *shaderPrg = nullptr;
1158 /* load the vertex program */
1159 Disable_Current_Shader();
1160 shaderPrg = GetShaderPrg("sphere_arb");
1161 glBindProgramARB(GL_VERTEX_PROGRAM_ARB, shaderPrg->vid);
1162
1163 /* load the fragment program */
1164 glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shaderPrg->fid);
1165
1166 /* load some safe initial values */
1167 glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, 0, 0.0F, 0.0F, 1.0F, 0.0F);
1168 glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, 0.5F, 2.0F, 0.0F, 0.0F);
1169
1170 glEnable(GL_VERTEX_PROGRAM_ARB);
1171 glEnable(GL_FRAGMENT_PROGRAM_ARB);
1172
1173 return shaderPrg;
1174 }
1175 #endif
1176
Get_ConnectorShader(int pass)1177 CShaderPrg *CShaderMgr::Get_ConnectorShader(int pass){
1178 return GetShaderPrg("connector", 1, pass);
1179 }
1180
Get_DefaultShader(int pass)1181 CShaderPrg *CShaderMgr::Get_DefaultShader(int pass){
1182 return GetShaderPrg("default", 1, pass);
1183 }
1184
Get_LineShader(int pass)1185 CShaderPrg *CShaderMgr::Get_LineShader(int pass){
1186 return GetShaderPrg("line", 1, pass);
1187 }
1188
Get_SurfaceShader(int pass)1189 CShaderPrg *CShaderMgr::Get_SurfaceShader(int pass){
1190 return GetShaderPrg("surface", 1, pass);
1191 }
1192
Get_CylinderShader(int pass,short set_current_shader)1193 CShaderPrg *CShaderMgr::Get_CylinderShader(int pass, short set_current_shader) {
1194 return GetShaderPrg("cylinder", set_current_shader, pass);
1195 }
1196
Get_CylinderNewShader(int pass,short set_current_shader)1197 CShaderPrg *CShaderMgr::Get_CylinderNewShader(int pass, short set_current_shader) {
1198 return GetShaderPrg("cylinder_new", set_current_shader, pass);
1199 }
1200
Get_Current_Shader()1201 CShaderPrg *CShaderMgr::Get_Current_Shader(){
1202 return current_shader;
1203 }
1204
Get_BackgroundShader()1205 CShaderPrg *CShaderMgr::Get_BackgroundShader(){
1206 return GetShaderPrg("bg");
1207 }
1208
Enable_BackgroundShader()1209 CShaderPrg *CShaderMgr::Enable_BackgroundShader(){
1210 CShaderPrg * shaderPrg = Get_BackgroundShader();
1211 if (!shaderPrg) return shaderPrg;
1212 shaderPrg->Enable();
1213
1214 glDisable(GL_DEPTH_TEST);
1215 shaderPrg->SetBgUniforms();
1216
1217 return shaderPrg;
1218 }
1219
Enable_TriLinesShader()1220 CShaderPrg *CShaderMgr::Enable_TriLinesShader() {
1221 CShaderPrg * shaderPrg = GetShaderPrg("trilines");
1222 if (!shaderPrg) return shaderPrg;
1223 shaderPrg->Enable();
1224 shaderPrg->SetBgUniforms();
1225 shaderPrg->Set_Stereo_And_AnaglyphMode();
1226 shaderPrg->Set_Matrices();
1227 {
1228 int width, height;
1229 SceneGetWidthHeightStereo(G, &width, &height);
1230
1231 shaderPrg->Set2f("inv_dimensions", 1.f/width, 1.f/height);
1232 }
1233 return shaderPrg;
1234 }
1235
1236 #ifndef _PYMOL_NO_AA_SHADERS
1237 #endif
1238
Enable_OITShader()1239 CShaderPrg *CShaderMgr::Enable_OITShader() {
1240 CShaderPrg * shaderPrg = GetShaderPrg("oit");
1241 if (!shaderPrg) return shaderPrg;
1242 shaderPrg->Enable();
1243
1244 constexpr GLuint accumTexUnit = 5;
1245 constexpr GLuint revealageTexUnit = 6;
1246 oit_pp->activateRTAsTexture(OIT_PostProcess::OITRT::ACCUM, accumTexUnit);
1247 oit_pp->activateRTAsTexture(OIT_PostProcess::OITRT::REVEALAGE, revealageTexUnit);
1248 shaderPrg->Set1i("accumTex", accumTexUnit);
1249 shaderPrg->Set1i("revealageTex", revealageTexUnit);
1250 shaderPrg->Set1f("isRight", stereo_flag > 0 ? 1. : 0);
1251 glEnable(GL_BLEND);
1252 glBlendFuncSeparate(
1253 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
1254 GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1255
1256 glDisable(GL_DEPTH_TEST);
1257 #ifndef PURE_OPENGL_ES_2
1258 glDisable(GL_ALPHA_TEST);
1259 #endif
1260 return shaderPrg;
1261 }
1262
Enable_OITCopyShader()1263 CShaderPrg *CShaderMgr::Enable_OITCopyShader() {
1264 CShaderPrg * shaderPrg = GetShaderPrg("copy");
1265 if (!shaderPrg) return shaderPrg;
1266 shaderPrg->Enable();
1267
1268 constexpr GLuint colorTexUnit = 7;
1269 activateOffscreenTexture(colorTexUnit);
1270 shaderPrg->Set1i("colorTex", colorTexUnit);
1271 if (G->ShaderMgr->stereo_blend){
1272 // for full-screen stereo
1273 glEnable(GL_BLEND);
1274 glBlendFunc(GL_ONE, GL_ONE);
1275 } else {
1276 glDisable(GL_BLEND);
1277 }
1278 glDisable(GL_DEPTH_TEST);
1279 #ifndef PURE_OPENGL_ES_2
1280 glDisable(GL_ALPHA_TEST);
1281 #endif
1282 return shaderPrg;
1283 }
1284
Enable_LabelShader(int pass)1285 CShaderPrg *CShaderMgr::Enable_LabelShader(int pass){
1286 CShaderPrg *shaderPrg;
1287 shaderPrg = Get_LabelShader(pass);
1288 if (!shaderPrg)
1289 return nullptr;
1290 shaderPrg->Enable();
1291 return Setup_LabelShader(shaderPrg);
1292 }
1293
Enable_ScreenShader()1294 CShaderPrg *CShaderMgr::Enable_ScreenShader(){
1295 CShaderPrg *shaderPrg;
1296 shaderPrg = Get_ScreenShader();
1297 if (!shaderPrg)
1298 return nullptr;
1299 shaderPrg->Enable();
1300
1301 int ortho_width, ortho_height;
1302 std::tie(ortho_width, ortho_height) = OrthoGetSize(*G->Ortho);
1303 shaderPrg->Set2f("t2PixelSize", 2.f / ortho_width, 2.f / ortho_height);
1304
1305 return Setup_LabelShader(shaderPrg);
1306 }
1307
Enable_RampShader()1308 CShaderPrg *CShaderMgr::Enable_RampShader(){
1309 CShaderPrg *shaderPrg;
1310 shaderPrg = Get_RampShader();
1311 if (!shaderPrg)
1312 return nullptr;
1313 shaderPrg->Enable();
1314 return Setup_LabelShader(shaderPrg);
1315 }
1316
Setup_LabelShader(CShaderPrg * shaderPrg)1317 CShaderPrg *CShaderMgr::Setup_LabelShader(CShaderPrg *shaderPrg) {
1318 int width = 0, height = 0;
1319
1320 shaderPrg->Set_Matrices();
1321
1322 glActiveTexture(GL_TEXTURE3);
1323 glBindTexture(GL_TEXTURE_2D, TextureGetTextTextureID(G));
1324 if (!(shaderPrg->uniform_set & 8)){
1325 shaderPrg->uniform_set |= 8;
1326 shaderPrg->Set1i("textureMap", 3);
1327 }
1328
1329 SceneGetWidthHeightStereo(G, &width, &height);
1330
1331 if (width)
1332 shaderPrg->Set2f("screenSize", width, height);
1333
1334 shaderPrg->SetBgUniforms();
1335
1336 {
1337 float v_scale = SceneGetScreenVertexScale(G, nullptr);
1338 shaderPrg->Set1f("screenOriginVertexScale", v_scale/2.f);
1339 }
1340 {
1341 float front, back;
1342 front = SceneGetCurrentFrontSafe(G);
1343 back = SceneGetCurrentBackSafe(G);
1344 shaderPrg->Set1f("front", front);
1345 shaderPrg->Set1f("clipRange", back - front);
1346 }
1347
1348 return shaderPrg;
1349 }
1350
Get_LabelShader(int pass)1351 CShaderPrg *CShaderMgr::Get_LabelShader(int pass){
1352 return GetShaderPrg("label", 1, pass);
1353 }
1354
Get_ScreenShader()1355 CShaderPrg *CShaderMgr::Get_ScreenShader() {
1356 if (is_picking)
1357 return nullptr;
1358 return GetShaderPrg("screen");
1359 }
1360
Get_RampShader()1361 CShaderPrg *CShaderMgr::Get_RampShader() {
1362 return GetShaderPrg("ramp");
1363 }
1364
Get_IndicatorShader()1365 CShaderPrg *CShaderMgr::Get_IndicatorShader() {
1366 return GetShaderPrg("indicator");
1367 }
1368
Enable_IndicatorShader()1369 CShaderPrg *CShaderMgr::Enable_IndicatorShader() {
1370 CShaderPrg * shaderPrg = Get_IndicatorShader();
1371 if (!shaderPrg) return shaderPrg;
1372 shaderPrg->Enable();
1373
1374 shaderPrg->Set_Stereo_And_AnaglyphMode();
1375 shaderPrg->Set_Matrices();
1376
1377 glActiveTexture(GL_TEXTURE3);
1378 glBindTexture(GL_TEXTURE_2D, TextureGetTextTextureID(G));
1379 if (!(shaderPrg->uniform_set & 8)){
1380 shaderPrg->Set1i("textureMap", 3);
1381 shaderPrg->uniform_set |= 8;
1382 }
1383 #ifdef PURE_OPENGL_ES_2
1384 shaderPrg->SetMat4fc("g_ModelViewMatrix", SceneGetModelViewMatrix(G));
1385 shaderPrg->SetMat4fc("g_ProjectionMatrix", SceneGetProjectionMatrix(G));
1386 #endif
1387
1388 return (shaderPrg);
1389 }
1390
1391
ResetUniformSet()1392 void CShaderMgr::ResetUniformSet() {
1393 for (auto & prog : programs) {
1394 prog.second->uniform_set = 0;
1395 }
1396 }
1397
SetIsPicking(int is_picking)1398 void CShaderMgr::SetIsPicking(int is_picking) {
1399 this->is_picking = is_picking;
1400 }
GetIsPicking()1401 int CShaderMgr::GetIsPicking() {
1402 return is_picking;
1403 }
1404
1405 #define LIGHTINGTEXTUREWIDTH 64
1406
1407 /*
1408 * Lighting setting indices are not contiguous, so we need a mapping array
1409 */
1410 int light_setting_indices[] = {
1411 cSetting_light, cSetting_light2, cSetting_light3, cSetting_light4,
1412 cSetting_light5, cSetting_light6, cSetting_light7, cSetting_light8,
1413 cSetting_light9
1414 };
1415
1416 /*
1417 * Generate and upload a precomputed vec2(ambient, specular) lighting texture.
1418 *
1419 * Must be equivalent to "ComputeLighting" in "compute_color_for_light.fs"
1420 */
Generate_LightingTexture()1421 void CShaderMgr::Generate_LightingTexture() {
1422 const int light_max = 10;
1423 int light_count = SettingGetGlobal_i(G, cSetting_light_count);
1424 int spec_count = SettingGetGlobal_i(G, cSetting_spec_count);
1425 float ambient = SettingGetGlobal_f(G, cSetting_ambient);
1426 float direct = SettingGetGlobal_f(G, cSetting_direct);
1427 float reflect = SettingGetGlobal_f(G, cSetting_reflect) * SceneGetReflectScaleValue(G, light_max);
1428 float shininess, spec_value;
1429 float shininess_0, spec_value_0;
1430 float diffuse, spec, shine;
1431 float power, power_0 = SettingGetGlobal_f(G, cSetting_power);
1432 float reflect_power = SettingGetGlobal_f(G, cSetting_reflect_power);
1433
1434 float light_positions[light_max][3] = {{0.F, 0.F, 1.F}};
1435
1436 // (ambient, specular) 2D texture
1437 unsigned char texture_AS[LIGHTINGTEXTUREWIDTH][LIGHTINGTEXTUREWIDTH][2];
1438
1439 SceneGetAdjustedLightValues(G,
1440 &spec_value,
1441 &shininess,
1442 &spec_value_0,
1443 &shininess_0,
1444 light_max);
1445
1446 if (light_count < 2) {
1447 light_count = 1;
1448 direct += reflect;
1449 } else if (light_count > light_max) {
1450 light_count = light_max;
1451 }
1452
1453 if(spec_count < 0) {
1454 spec_count = light_count - 1;
1455 }
1456
1457 for (int i = 1; i < light_count; ++i) {
1458 const float * setting = SettingGetGlobal_3fv(G, light_setting_indices[i - 1]);
1459 copy3f(setting, light_positions[i]);
1460 normalize3f(light_positions[i]);
1461 invert3f(light_positions[i]);
1462 }
1463
1464 glGenTextures(1, &lightingTexture);
1465
1466 glActiveTexture(GL_TEXTURE1);
1467 glBindTexture(GL_TEXTURE_CUBE_MAP, lightingTexture);
1468 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1469 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1470
1471 #ifndef PURE_OPENGL_ES_2
1472 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
1473 #else
1474 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1475 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1476 #endif
1477
1478 float normal[3];
1479 const float vz = LIGHTINGTEXTUREWIDTH / 2;
1480
1481 for (int face = 0; face < 6; ++face) {
1482 for (int y = 0; y < LIGHTINGTEXTUREWIDTH; ++y) {
1483 for (int x = 0; x < LIGHTINGTEXTUREWIDTH; ++x) {
1484
1485 float vx = x + .5f - vz;
1486 float vy = -(y + .5f - vz);
1487
1488 switch (face) {
1489 case 0: set3f(normal, vz, vy, -vx); break;
1490 case 1: set3f(normal, -vz, vy, vx); break;
1491 case 2: set3f(normal, vx, vz, -vy); break;
1492 case 3: set3f(normal, vx, -vz, vy); break;
1493 case 4: set3f(normal, vx, vy, vz); break;
1494 case 5: set3f(normal, -vx, vy, -vz); break;
1495 }
1496
1497 normalize3f(normal);
1498
1499 float ambient_sum = ambient;
1500 float specular_sum = 0.F;
1501
1502 for (int i = 0; i < light_count; ++i) {
1503 if (i == 0) {
1504 diffuse = direct;
1505 spec = spec_value_0;
1506 shine = shininess_0;
1507 power = power_0;
1508 } else {
1509 diffuse = reflect;
1510 spec = spec_value;
1511 shine = shininess;
1512 power = reflect_power;
1513 }
1514
1515 // light direction (normalized)
1516 const float * L = light_positions[i];
1517
1518 // cosine of angle between normal and light
1519 float NdotL = dot_product3f(normal, L);
1520
1521 // normal points away from light
1522 if (NdotL <= 0.0)
1523 continue;
1524
1525 // power/reflect_power, was ray trace only until 1.7.7
1526 NdotL = pow(NdotL, power);
1527
1528 // diffuse
1529 ambient_sum += NdotL * diffuse;
1530
1531 // specular
1532 if (i <= spec_count) {
1533 // H = normalize(L + vec3(0., 0., 1.));
1534 float H[] = {0., 0., 1.};
1535 add3f(L, H, H);
1536 normalize3f(H);
1537
1538 float NdotH = std::max(dot_product3f(normal, H), 0.f);
1539 specular_sum += spec * pow(NdotH, shine);
1540 }
1541 }
1542
1543 texture_AS[y][x][0] = pymol_roundf(255.F * std::min(1.F, ambient_sum));
1544 texture_AS[y][x][1] = pymol_roundf(255.F * std::min(1.F, specular_sum));
1545 }
1546 }
1547
1548 glTexImage2D(
1549 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
1550 /* level */ 0,
1551 /* internalformat */ GL_LUMINANCE_ALPHA,
1552 /* width */ LIGHTINGTEXTUREWIDTH,
1553 /* height */ LIGHTINGTEXTUREWIDTH,
1554 /* border */ 0,
1555 /* format */ GL_LUMINANCE_ALPHA,
1556 /* type */ GL_UNSIGNED_BYTE,
1557 /* data */ (void*) texture_AS);
1558 }
1559 }
1560
Set_Reload_Bits(int bits)1561 void CShaderMgr::Set_Reload_Bits(int bits){
1562 reload_bits |= bits;
1563 }
1564
Check_Reload()1565 void CShaderMgr::Check_Reload() {
1566 if(!SettingGetGlobal_b(G, cSetting_use_shaders)) {
1567 return;
1568 }
1569
1570 if (reload_bits){
1571 if (reload_bits == RELOAD_ALL_SHADERS) {
1572 for (auto& prog : programs)
1573 prog.second->is_valid = false;
1574 shader_cache_processed.clear();
1575 }
1576
1577 Reload_All_Shaders();
1578 reload_bits = 0;
1579 }
1580 }
1581
GetLineWidthRange()1582 GLfloat *CShaderMgr::GetLineWidthRange() {
1583 return line_width_range;
1584 }
1585
1586 #ifndef _PYMOL_NO_AA_SHADERS
1587 #endif
1588
1589 /*
1590 * Register filename -> shader dependencies for `shader`
1591 */
RegisterDependantFileNames(CShaderPrg * shader)1592 void CShaderMgr::RegisterDependantFileNames(CShaderPrg * shader) {
1593 shader_deps[shader->vertfile].push_back(shader->name);
1594 shader_deps[shader->fragfile].push_back(shader->name);
1595 if (!shader->geomfile.empty())
1596 shader_deps[shader->geomfile].push_back(shader->name);
1597 }
1598
1599 /*
1600 * Recursive function to insert `filename` and all the files where
1601 * `filename` is included into the given output vector.
1602 */
CollectDependantFileNames(const std::string & filename,std::vector<std::string> & filenames)1603 void CShaderMgr::CollectDependantFileNames(const std::string &filename,
1604 std::vector<std::string> &filenames) {
1605 auto it = include_deps.find(filename);
1606 if (it != include_deps.end()) {
1607 for (const char ** filenameptr = it->second;
1608 *filenameptr; ++filenameptr) {
1609 CollectDependantFileNames(*filenameptr, filenames);
1610 }
1611 }
1612 filenames.push_back(filename);
1613 }
1614
1615 /*
1616 * Make derived shaders for all shaders that depend on `variable`
1617 */
MakeDerivatives(const std::string & suffix,const std::string & variable)1618 void CShaderMgr::MakeDerivatives(const std::string &suffix, const std::string &variable) {
1619 std::set<std::string> shadernames;
1620 std::vector<std::string> filenames;
1621
1622 // variable -> files
1623 for (const char ** filenameptr = ifdef_deps[variable];
1624 *filenameptr; ++filenameptr) {
1625 CollectDependantFileNames(*filenameptr, filenames);
1626 }
1627
1628 // files -> shaders
1629 for (auto& filename : filenames) {
1630 auto &vec = shader_deps[filename];
1631 for (auto& n_it : vec) {
1632 shadernames.insert(n_it);
1633 }
1634 }
1635
1636 // create shader derivatives
1637 for (const auto& shadername : shadernames) {
1638 auto shader = programs[shadername]->DerivativeCopy(shadername + suffix, variable);
1639 programs[shader->name] = shader;
1640
1641 // register dependency
1642 RegisterDependantFileNames(shader);
1643 }
1644 }
1645
1646 /*
1647 * Reload the derivative shaders for `variable`
1648 */
Reload_Derivatives(const std::string & variable,bool value)1649 void CShaderMgr::Reload_Derivatives(const std::string &variable, bool value) {
1650 SetPreprocVar(variable, value, false);
1651
1652 for (auto& prog : programs) {
1653 if (prog.second->derivative == variable)
1654 prog.second->reload();
1655 }
1656
1657 SetPreprocVar(variable, !value, false);
1658 }
1659
1660 /*
1661 * Removes `filename` and all it's parents from the shader source cache,
1662 * and if `invshaders` is true, also clear the `is_valid` flag for all
1663 * shader infos that depend on `filename`.
1664 */
ShaderSourceInvalidate(const char * filename,bool invshaders)1665 void CShaderMgr::ShaderSourceInvalidate(const char * filename, bool invshaders) {
1666 // recursion for includes
1667 auto it = include_deps.find(filename);
1668 if (it != include_deps.end()) {
1669 for (const char ** filenameptr = it->second;
1670 *filenameptr; ++filenameptr) {
1671 ShaderSourceInvalidate(*filenameptr, invshaders);
1672 }
1673 }
1674
1675 // invalidate shaders
1676 if (invshaders) {
1677 auto &vec = shader_deps[filename];
1678 for (const auto& shadername : vec) {
1679 programs[shadername]->is_valid = false;
1680 }
1681 }
1682
1683 // invalidate source file
1684 auto repl_it = shader_cache_processed.find(filename);
1685 if (repl_it != shader_cache_processed.end()) {
1686 shader_cache_processed.erase(repl_it);
1687 }
1688 }
1689
1690 /*
1691 * Set the value for the #ifdef variable `key` and if the value has changed,
1692 * then invalidate all its dependant shader source files.
1693 */
SetPreprocVar(const std::string & key,bool value,bool invshaders)1694 void CShaderMgr::SetPreprocVar(const std::string &key, bool value, bool invshaders) {
1695 auto &ref = preproc_vars[key];
1696 if (ref != value) {
1697 for (const char ** filenameptr = ifdef_deps[key];
1698 *filenameptr; ++filenameptr) {
1699 ShaderSourceInvalidate(*filenameptr, invshaders);
1700 }
1701 ref = value;
1702 }
1703 }
1704
1705 /*
1706 * Insert `filename` -> `contents` (processed source) into the shader source
1707 * cache and invalidate its parents
1708 */
SetShaderSource(const char * filename,const std::string & contents)1709 void CShaderMgr::SetShaderSource(const char * filename, const std::string &contents) {
1710 ShaderSourceInvalidate(filename);
1711 shader_cache_processed[filename] = contents;
1712 }
1713
bindGPUBuffer(size_t hashid)1714 void CShaderMgr::bindGPUBuffer(size_t hashid) {
1715 auto search = _gpu_object_map.find(hashid);
1716 if (search != _gpu_object_map.end())
1717 search->second->bind();
1718 }
1719
freeGPUBuffer(size_t hashid)1720 void CShaderMgr::freeGPUBuffer(size_t hashid) {
1721 if (!hashid)
1722 return;
1723 LOCK_GUARD_MUTEX(lock, gpu_objects_to_free_mutex);
1724 _gpu_objects_to_free_vector.push_back(hashid);
1725
1726 #ifdef _WEBGL
1727 freeAllGPUBuffers(); // immediate free on web
1728 #endif
1729 }
1730
freeGPUBuffers(std::vector<size_t> && hashids)1731 void CShaderMgr::freeGPUBuffers(std::vector<size_t> &&hashids) {
1732 LOCK_GUARD_MUTEX(lock, gpu_objects_to_free_mutex);
1733 _gpu_objects_to_free_vector.insert(_gpu_objects_to_free_vector.end(),
1734 hashids.begin(), hashids.end());
1735 #ifdef _WEBGL
1736 freeAllGPUBuffers(); // immediate free on web
1737 #endif
1738 }
1739
freeGPUBuffers(size_t * arr,size_t len)1740 void CShaderMgr::freeGPUBuffers(size_t * arr, size_t len) {
1741 for (unsigned int i = 0; i < len; ++i)
1742 freeGPUBuffer(arr[i]);
1743 }
1744
freeAllGPUBuffers()1745 void CShaderMgr::freeAllGPUBuffers() {
1746 LOCK_GUARD_MUTEX(lock, gpu_objects_to_free_mutex);
1747 for (auto hashid : _gpu_objects_to_free_vector) {
1748 auto search = _gpu_object_map.find(hashid);
1749 if (search != _gpu_object_map.end()) {
1750 if (search->second)
1751 delete search->second;
1752 _gpu_object_map.erase(search);
1753 }
1754 }
1755 _gpu_objects_to_free_vector.clear();
1756 }
1757
GetAttributeUID(const char * name)1758 int CShaderMgr::GetAttributeUID(const char * name)
1759 {
1760 auto uloc = attribute_uids_by_name.find(name);
1761 if (uloc != attribute_uids_by_name.end())
1762 return uloc->second;
1763
1764 int uid = attribute_uids_by_name.size() + 1;
1765 attribute_uids_by_name[name] = uid;
1766 attribute_uids[uid] = name;
1767 return uid;
1768 }
GetAttributeName(int uid)1769 const char *CShaderMgr::GetAttributeName(int uid)
1770 {
1771 auto uloc = attribute_uids.find(uid);
1772 if (uloc == attribute_uids.end())
1773 return nullptr;
1774 return attribute_uids[uid].c_str();
1775 }
1776
1777 // SceneRenderBindToOffscreen
bindOffscreen(int width,int height,GridInfo * grid)1778 void CShaderMgr::bindOffscreen(int width, int height, GridInfo *grid) {
1779 using namespace tex;
1780 renderTarget_t::shape_type req_size(width, height);
1781 renderTarget_t* rt = nullptr;
1782
1783 #ifndef _PYMOL_NO_AA_SHADERS
1784 #endif
1785
1786 // Doesn't exist, create
1787 if (!offscreen_rt) {
1788 CGOFree(G->Scene->offscreenCGO);
1789 rt = newGPUBuffer<renderTarget_t>(req_size);
1790 rt->layout({ { 4, rt_layout_t::UBYTE } });
1791 offscreen_rt = rt->get_hash_id();
1792 } else {
1793 rt = getGPUBuffer<renderTarget_t>(offscreen_rt);
1794
1795 // resize
1796 if (req_size != rt->size()) {
1797 rt->resize(req_size);
1798 #ifndef _PYMOL_NO_AA_SHADERS
1799 #endif
1800 }
1801 }
1802
1803 if (rt)
1804 rt->bind(!stereo_blend);
1805 glEnable(GL_BLEND);
1806
1807 SceneInitializeViewport(G, 1);
1808 if (grid->active) {
1809 grid->cur_view[0] = grid->cur_view[1] = 0;
1810 grid->cur_view[2] = req_size.x;
1811 grid->cur_view[3] = req_size.y;
1812 }
1813 }
1814
1815 // SceneRenderBindToOffscreenOIT
bindOffscreenOIT(int width,int height,int drawbuf)1816 void CShaderMgr::bindOffscreenOIT(int width, int height, int drawbuf) {
1817 using namespace tex;
1818
1819 renderTarget_t::shape_type req_size(width, height);
1820
1821 if(!oit_pp || oit_pp->size() != req_size) {
1822 oit_pp = pymol::make_unique<OIT_PostProcess>(
1823 width, height, getGPUBuffer<renderTarget_t>(offscreen_rt)->_rbo);
1824 } else {
1825 if (!TM3_IS_ONEBUF) {
1826 drawbuf = 1;
1827 }
1828 oit_pp->bindFBORBO(drawbuf - 1);
1829 }
1830 }
1831
activateOffscreenTexture(GLuint textureIdx)1832 void CShaderMgr::activateOffscreenTexture(GLuint textureIdx) {
1833 glActiveTexture(GL_TEXTURE0 + textureIdx);
1834 auto t = getGPUBuffer<renderTarget_t>(offscreen_rt);
1835 if (t->_textures[0])
1836 t->_textures[0]->bind();
1837 }
1838
Disable_Current_Shader()1839 void CShaderMgr::Disable_Current_Shader()
1840 {
1841 if(current_shader){
1842 current_shader->Disable();
1843 }
1844 }
1845