445 lines
14 KiB
C++
445 lines
14 KiB
C++
/*
|
|
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 <map>
|
|
#include <set>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
|
|
#ifdef _WEBGL
|
|
#define GET_FRAGDEPTH_SUPPORT() webpymol_get_fragdepth_support()
|
|
#else
|
|
#define GET_FRAGDEPTH_SUPPORT() 1
|
|
#endif
|
|
|
|
#if !defined(_WEBGL)
|
|
#include <mutex>
|
|
#define LOCK_GUARD_MUTEX(name, var) std::lock_guard<std::mutex> 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<GeometryShaderParams> geomParams;
|
|
pymol::copyable_ptr<TessellationShaderParams> tessParams;
|
|
|
|
std::map<int, std::string> 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<GeometryShaderParams> geomParams = nullptr,
|
|
pymol::copyable_ptr<TessellationShaderParams> 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<std::string, int> uniforms;
|
|
std::map<std::string, int> 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 <typename T, typename... TArgs>
|
|
T * newGPUBuffer(TArgs&&... args) {
|
|
std::hash<gpuBuffer_t *> hash_fn;
|
|
T * buffer = new T(std::forward<TArgs>(args)...);
|
|
auto bufptr = dynamic_cast<gpuBuffer_t *>(buffer);
|
|
const size_t hashid = hash_fn(bufptr);
|
|
buffer->set_hash_id(hashid);
|
|
_gpu_object_map[hashid] = buffer;
|
|
return buffer;
|
|
}
|
|
|
|
template <typename T>
|
|
T * getGPUBuffer(size_t hashid) {
|
|
auto search = _gpu_object_map.find(hashid);
|
|
if (search != _gpu_object_map.end())
|
|
return dynamic_cast<T*>(search->second);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
void bindGPUBuffer(size_t hashid);
|
|
void freeGPUBuffer(size_t handle);
|
|
void freeGPUBuffers(std::vector<size_t> && 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<std::string, const char*>* GetRawShaderCache();
|
|
|
|
inline static std::uint32_t OpenGLDefaultFramebufferID = 0;
|
|
|
|
private:
|
|
void freeAllGPUBuffers();
|
|
void RegisterDependantFileNames(CShaderPrg * shader);
|
|
void CollectDependantFileNames(const std::string &filename, std::vector<std::string> &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<GLuint> 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<size_t, gpuBuffer_t*> _gpu_object_map;
|
|
std::vector<size_t> _gpu_objects_to_free_vector;
|
|
public:
|
|
std::map<std::string, CShaderPrg*> programs;
|
|
|
|
std::map<int, std::string> attribute_uids;
|
|
std::map<const std::string, int> 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<std::string, std::vector<std::string> > 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<PostProcess> smaa_pp;
|
|
#endif
|
|
std::unique_ptr<PostProcess> 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<unsigned char> 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
|