/* A* ------------------------------------------------------------------- B* This file contains source code for the PyMOL computer program C* copyright Schrodinger, LLC. D* ------------------------------------------------------------------- E* It is unlawful to modify or remove this copyright notice. F* ------------------------------------------------------------------- G* Please see the accompanying LICENSE file for further information. H* ------------------------------------------------------------------- I* Additional authors of this source file include: -* -* -* Z* ------------------------------------------------------------------- */ #ifndef _SHADER_MGR_H #define _SHADER_MGR_H #include "os_gl.h" #include "PyMOLGlobals.h" #include "Rep.h" #include "GenericBuffer.h" #include "SceneDef.h" #include "ShaderPreprocessor.h" #include "PostProcess.h" #include #include #include #include #ifdef _WEBGL #define GET_FRAGDEPTH_SUPPORT() webpymol_get_fragdepth_support() #else #define GET_FRAGDEPTH_SUPPORT() 1 #endif #if !defined(_WEBGL) #include #define LOCK_GUARD_MUTEX(name, var) std::lock_guard name(var) #else #define LOCK_GUARD_MUTEX(name, var) #endif class CShaderPrg { public: struct GeometryShaderParams { std::string file = ""; GLenum input{}; GLenum output{}; int numVertsOut{}; GLuint id{}; }; struct TessellationShaderParams { std::string controlFile = ""; std::string evaluationFile = ""; GLuint controlID{}; GLuint evaluationID{}; }; const std::string name, vertfile, fragfile; pymol::copyable_ptr geomParams; pymol::copyable_ptr tessParams; std::map uniformLocations; std::string derivative; bool is_valid; bool is_linked; CShaderPrg(PyMOLGlobals* G_, const std::string& name, const std::string& vertfile, const std::string& fragfile, pymol::copyable_ptr geomParams = nullptr, pymol::copyable_ptr tessParams = nullptr) : name(name) , geomParams(std::move(geomParams)) , tessParams(std::move(tessParams)) , vertfile(vertfile) , fragfile(fragfile) , is_valid(false) , is_linked(false) , G(G_) { } bool reload(); /* * Create a derivative copy. This will reload with ShaderMgr::Reload_Derivatives. */ CShaderPrg* DerivativeCopy( const std::string& name, const std::string& variable) { CShaderPrg* copy = new CShaderPrg(G, name, vertfile, fragfile, geomParams, tessParams); copy->derivative = variable; return copy; } /* Enable */ int Enable(); /* Disable */ int Disable(); /* Link and IsLinked */ int Link(); int IsLinked(); /* accessors/mutators/uniform setters */ int Set1i(const char * name, int i); int Set1f(const char * name, float f); int Set2f(const char * name, float f1, float f2); int Set3f(const char * name, float f1, float f2, float f3); int Set4fv(const char * name, const float *f); int Set3fv(const char * name, const float *f); int Set4f(const char * name, float f1, float f2, float f3, float f4); int SetMat3fc(const char * name, const GLfloat * m); int SetMat4fc(const char * name, const GLfloat * m); int GetUniformLocation(const char * name); int GetAttribLocation(const char * name); void SetAttrib4fLocation(const char * name, float f1, float f2, float f3, float f4); void SetAttrib1fLocation(const char * name, float f1); int SetLightingEnabled(int); void SetBgUniforms(); void Set_Stereo_And_AnaglyphMode(); void Set_AnaglyphMode(int mode); void Set_Matrices(); void Set_Specular_Values(); void Invalidate(); void ErrorMsgWithShaderInfoLog(const GLuint sid, const char * msg); public: PyMOLGlobals * G; /* openGL assigned id */ int id{}; /* openGL fragment and vertex shader ids */ GLuint vid{}; GLuint fid{}; std::map uniforms; std::map attributes; int uniform_set{}; // bitmask }; /* ============================================================================ * CShaderMgr class -- simple ShaderMgr for PyMOL * ============================================================================*/ class CShaderMgr { public: CShaderMgr(PyMOLGlobals * G); ~CShaderMgr(); void Config(); void Set_Reload_Bits(int bits); void Check_Reload(); GLfloat *GetLineWidthRange(); template T * newGPUBuffer(TArgs&&... args) { std::hash hash_fn; T * buffer = new T(std::forward(args)...); auto bufptr = dynamic_cast(buffer); const size_t hashid = hash_fn(bufptr); buffer->set_hash_id(hashid); _gpu_object_map[hashid] = buffer; return buffer; } template T * getGPUBuffer(size_t hashid) { auto search = _gpu_object_map.find(hashid); if (search != _gpu_object_map.end()) return dynamic_cast(search->second); else return nullptr; } void bindGPUBuffer(size_t hashid); void freeGPUBuffer(size_t handle); void freeGPUBuffers(std::vector && handles); void freeGPUBuffers(size_t * arr, size_t len); #ifndef _PYMOL_NO_AA_SHADERS bool Reload_SMAA_Shaders(); int SMAAShadersPresent(); CShaderPrg *Enable_FXAAShader(); CShaderPrg *Enable_SMAA1Shader(); CShaderPrg *Enable_SMAA2Shader(); CShaderPrg *Enable_SMAA3Shader(); CShaderPrg *Enable_SMAAShader(const char *shaderName); #endif void Reload_Shader_Variables(); /* AddShader -- Adds to the global shader library */ int AddShaderPrg(CShaderPrg * s); /* RemoveShader -- Removes shader program by name */ int RemoveShaderPrg(const std::string& name); /* GetShaderPrg -- gets a ptr to the installed shader */ CShaderPrg * GetShaderPrg(std::string name, short set_current_shader = 1, RenderPass pass = RenderPass::Antialias); int ShaderPrgExists(const char * name); /* runtime check for shaders */ int ShadersPresent(); int GeometryShadersPresent(); void AddVBOsToFree(GLuint *vboid, int nvbos); void AddVBOToFree(GLuint vboid); void FreeAllVBOs(); CShaderPrg *Enable_DefaultShader(RenderPass pass); CShaderPrg *Enable_LineShader(RenderPass pass); CShaderPrg *Enable_SurfaceShader(RenderPass pass); CShaderPrg *Enable_DefaultShaderWithSettings(const CSetting * set1, const CSetting * set2, RenderPass pass); CShaderPrg *Enable_CylinderShader(const char *, RenderPass pass); CShaderPrg *Enable_CylinderShader(RenderPass pass); CShaderPrg *Enable_DefaultSphereShader(RenderPass pass); CShaderPrg *Enable_RampShader(); CShaderPrg *Enable_ConnectorShader(RenderPass pass); CShaderPrg *Enable_TriLinesShader(); CShaderPrg *Enable_ScreenShader(); CShaderPrg *Enable_LabelShader(RenderPass pass); CShaderPrg *Enable_OITShader(); CShaderPrg *Enable_OITCopyShader(); CShaderPrg *Enable_IndicatorShader(); CShaderPrg *Enable_BackgroundShader(); CShaderPrg* Enable_BezierShader(); void Disable_Current_Shader(); CShaderPrg *Get_ScreenShader(); CShaderPrg *Get_ConnectorShader(RenderPass pass); CShaderPrg *Get_DefaultShader(RenderPass pass); CShaderPrg *Get_LineShader(RenderPass pass); CShaderPrg *Get_SurfaceShader(RenderPass pass); CShaderPrg *Get_CylinderShader(RenderPass pass, short set_current_shader=1); CShaderPrg *Get_CylinderNewShader(RenderPass pass, short set_current_shader=1); CShaderPrg *Get_DefaultSphereShader(RenderPass pass); CShaderPrg *Get_RampShader(); CShaderPrg *Get_Current_Shader(); CShaderPrg *Get_IndicatorShader(); CShaderPrg *Get_BackgroundShader(); CShaderPrg *Get_LabelShader(RenderPass pass); CShaderPrg* Get_BezierShader(); void Reload_CallComputeColorForLight(); void Reload_All_Shaders(); void Invalidate_All_Shaders(); void ResetUniformSet(); void CShaderPrg_SetIsPicking(int is_picking); void Generate_LightingTexture(); std::string GetShaderSource(const std::string &filename); CShaderPrg *Setup_LabelShader(CShaderPrg *shaderPrg); CShaderPrg *Setup_DefaultShader(CShaderPrg *shaderPrg, const CSetting *set1, const CSetting *set2); void SetIsPicking(int is_picking); int GetIsPicking(); void SetPreprocVar(const std::string &key, bool value, bool invshaders = true); /** * @return a map of shader filenames to their raw source code */ static std::map* GetRawShaderCache(); inline static std::uint32_t OpenGLDefaultFramebufferID = 0; private: void freeAllGPUBuffers(); void RegisterDependantFileNames(CShaderPrg * shader); void CollectDependantFileNames(const std::string &filename, std::vector &filenames); void MakeDerivatives(const std::string &suffix, const std::string &variable); void Reload_Derivatives(const std::string &variable, bool value = true); void ShaderSourceInvalidate(const char * filename, bool invshaders = true); void SetShaderSource(const char * filename, const std::string &contents); public: PyMOLGlobals * G; int shaders_present; #ifndef _WEBGL // for deleting buffers in the correct thread std::vector vbos_to_free; std::mutex vbos_to_free_mutex; std::mutex gpu_objects_to_free_mutex; #endif CShaderPrg *current_shader; int is_picking; GLuint lightingTexture; /* These lookups and arrays are used to dynamically change the shaders based on preprocessor-like statements within the shaders. These need string lookups. */ private: ShaderPreprocessor m_shaderPreprocessor; std::unordered_map _gpu_object_map; std::vector _gpu_objects_to_free_vector; public: std::map programs; std::map attribute_uids; std::map attribute_uids_by_name; int GetAttributeUID(const char * name); const char *GetAttributeName(int); short print_warnings; int reload_bits; GLfloat line_width_range[2]; short stereo_flag; /* -1 left; 0 = off; 1 = right */ short stereo_blend; /* 0 - no blend, 1 - blend : for right eye stereo in full-screen e.g., anaglyph */ bool stereo_draw_buffer_pass; // for glDrawBuffer (e.g. GL_BACK, unless we're using QOpenGLWidget) GLFramebufferConfig defaultBackbuffer{}; // Default framebuffer configuration GLFramebufferConfig currentFBConfig{}; // Current framebuffer configuration GLFramebufferConfig topLevelConfig{}; // Final render target in draw loop // (currently only known by Ortho) private: bool is_configured { false }; public: bool IsConfigured(){ return is_configured; } // filename -> used by shader std::map > shader_deps; // Post process render targets std::size_t offscreen_rt { 0 }; //Texture before postprocessing; std::size_t offscreen_ortho_rt{}; std::size_t offscreen_sized_image_rt{}; #ifndef _PYMOL_NO_AA_SHADERS std::unique_ptr smaa_pp; #endif std::unique_ptr oit_pp; void bindOffscreen(int width, int height, GridInfo * grid); void bindOffscreenOIT(int width, int height, int drawbuf = 0); /** * @brief Binds an offscreen render target for UI overlay rendering * @param extent extent of the offscreen render target * @param clear whether to clear the offscreen render target * @return framebuffer configuration of bound ortho offscreen render target */ GLFramebufferConfig bindOffscreenOrtho(const Extent2D& extent, bool clear = true); /** * @brief Binds an offscreen render target for sized rendering * @param extent extent of the offscreen render target * @param clear whether to clear the offscreen render target * @return framebuffer configuration of bound offscreen render target */ GLFramebufferConfig bindOffscreenSizedImage(const Extent2D& extent, bool clear = true); /** * @brief Reads pixel data from framebuffer * @param rect the rectangle to read from * @param srcConfig the framebuffer configuration to read from * @return pixel data in RGBA format */ std::vector readPixelsFrom( PyMOLGlobals* G, const Rect2D& rect, const GLFramebufferConfig& srcConfig); /** * @brief Draws pixel data to framebuffer * @param rect the rectangle to draw to * @param srcPixels the pixel data (RGBA) to draw * @param dstConfig the framebuffer configuration to draw to */ void drawPixelsTo(PyMOLGlobals* G, const Rect2D& rect, const std::byte* srcPixels, const GLFramebufferConfig& dstConfig); /** * Activates/Binds offscreen render target. * @param textureIdx offset of texture unit to assign (0 for GL_TEXTURE0, 1 * for GL_TEXTURE1, etc...) * @note: indices should preferably be passed in as enum or named variable for * clarity */ void activateOffscreenTexture(GLuint textureIdx); /** * Sets the current draw buffer for rendering * @param drawBuffer Buffer to draw to (e.g. GL_BACK) * @note: This currently assumes the default framebuffer. Prefer * GLFramebufferConfig coverload. */ void setDrawBuffer(GLenum drawBuffer); /** * Sets the current framebuffer or draw buffer for rendering * @param drawBuffer Framebuffer to draw to */ void setDrawBuffer(GLFramebufferConfig config); }; bool ShaderMgrInit(PyMOLGlobals * G); /* for reload_bits */ enum { RELOAD_VARIABLES = 0x01, RELOAD_CALLCOMPUTELIGHTING = 0x02, RELOAD_ALL_SHADERS = 0xff, }; #define VERTEX_POS_SIZE 3 #define VERTEX_COLOR_SIZE 4 #define VERTEX_POS 0 #define VERTEX_NORMAL 1 #define VERTEX_COLOR 2 #define CYLINDER_VERTEX1 0 #define CYLINDER_VERTEX2 1 #define CYLINDER_COLOR 2 #define CYLINDER_COLOR2 3 #define CYLINDER_RADIUS 4 #define CYLINDER_CAP 5 #define RAMP_OFFSETPT 0 #endif // vi:sw=2:expandtab