12#ifndef GAMP_GLSLSHADERSTATE_HPP_
13#define GAMP_GLSLSHADERSTATE_HPP_
32 using namespace gamp::render::gl;
33 using namespace gamp::render::gl::data;
51 constexpr DataLoc(DataLocNone) noexcept
52 : m_name(), m_data(
nullptr), m_location(-1), m_enabled(
false)
56 : m_name(name), m_data(
nullptr), m_location(loc), m_enabled(
false)
60 : m_name(d->name()), m_data(d), m_location(d->location()), m_enabled(
false)
63 constexpr bool valid() const noexcept {
return !m_name.empty(); }
64 constexpr operator bool() const noexcept {
return valid(); }
66 constexpr stringview_t name() const noexcept {
return m_name; }
67 constexpr const GLArrayDataSRef& data() const noexcept {
return m_data; }
69 constexpr GLint location() const noexcept {
return m_location; }
70 constexpr bool enabled() const noexcept {
return m_enabled; }
72 void setData(
const GLArrayDataSRef &d)
noexcept {
if( valid() ) { m_data = d; } }
73 void setLocation(GLint l)
noexcept {
if( valid() ) { m_location =
l; } }
74 void setEnabled(
bool v)
noexcept {
79 std::string toString() const noexcept {
80 return "name: "+std::string(m_name)+
", valid "+
jau::to_string(valid())+
81 ", loc "+std::to_string(m_location)+
", enabled "+
jau::to_string(m_enabled)+
85 typedef std::reference_wrapper<DataLoc> DataLocRef;
138 if(m_shaderProgram->linked()) {
139 m_shaderProgram->useProgram(
gl,
true);
140 if(m_resetAllShaderData) {
141 resetAllAttributes(
gl);
142 resetAllUniforms(
gl);
145 if(m_resetAllShaderData) {
146 setAllAttributes(
gl);
148 if(!m_shaderProgram->link(
gl,
verbose())) {
151 m_shaderProgram->useProgram(
gl,
true);
152 if(m_resetAllShaderData) {
153 resetAllUniforms(
gl);
156 m_resetAllShaderData =
false;
158 m_shaderProgram->useProgram(
gl,
false);
164 return m_shaderProgram ? m_shaderProgram->linked() :
false;
169 return m_shaderProgram ? m_shaderProgram->inUse() :
false;
190 const size_t curId = m_shaderProgram ? m_shaderProgram->id() : 0;
191 const size_t newId = prog ? prog->id() : 0;
192 jau_INFO_PRINT(
"ShaderState: attachShaderProgram: %zu -> %zu (enable: %d)\n\t%s\n\t%s",
193 curId, newId, enable,
194 (m_shaderProgram ? m_shaderProgram->toString() :
"null"),
195 (prog ? prog->toString() :
"null"));
197 if(m_shaderProgram) {
198 if(m_shaderProgram == prog) {
204 jau_INFO_PRINT(
"ShaderState: attachShaderProgram: No switch, equal id: %zu , enabling %d",
205 m_shaderProgram->id(), enable);
209 if(m_shaderProgram->inUse()) {
211 m_shaderProgram->notifyNotInUse();
217 m_resetAllShaderData =
true;
221 m_shaderProgram = prog;
223 if(m_shaderProgram) {
226 if(m_resetAllShaderData || enable) {
293 if(m_shaderProgram && m_shaderProgram->linked() ) {
294 m_shaderProgram->useProgram(
gl,
false);
296 if(destroyBoundAttributes) {
304 m_shaderProgram->release(
gl, destroyShaderCode);
327 return m_activeAttribMap.get(
name).data();
344 return m_activeAttribMap.get(
name).location();
349 return updateDataLoc(m_activeAttribMap.get(
data->name()),
data,
true);
351 impl::DataLoc& updateDataLoc(impl::DataLoc &dl,
const GLArrayDataSRef &
data,
bool mapNewInstance) {
353 if( !dl.data() || dl.data() !=
data ) {
357 dl.setLocation(
data->location());
361 if( mapNewInstance) {
362 return m_activeAttribMap.put2(
data->name(), impl::DataLoc(
data));
364 return m_activeAttribMap.novalue();
367 void updateDataLoc(impl::DataLoc &dl, GLint location) {
369 dl.data()->setLocation(location);
371 dl.setLocation(location);
376 return attribute == m_activeAttribMap.get(attribute->name()).data();
404 m_managedAttributes.push_back(attr);
406 std::erase(m_managedAttributes, attr);
408 attr->associate(*
this, enable);
413 return m_managedAttributes.end() != std::find(m_managedAttributes.begin(), m_managedAttributes.end(), attribute);
433 attr->setLocation(
gl, m_shaderProgram->program(), location);
434 updateAttributeCache(attr);
435 ::glBindAttribLocation(m_shaderProgram->program(), location,
string_t(
name).c_str());
456 return resolveLocation2(
gl,
name,
false).location();
461 impl::DataLoc *dl = &m_activeAttribMap.get(
name);
462 GLint location = dl->location();
466 location = ::glGetAttribLocation(m_shaderProgram->program(),
string_t(
name).c_str());
467 impl::DataLoc dl_new(
name, location);
469 updateDataLoc(*dl, location);
473 if( 0 <= location ) {
474 dl = &m_activeAttribMap.put2(
name, *dl);
480 dl = &m_activeAttribMap.put2(
name, *dl);
482 dl = &m_activeAttribMap.novalue();
508 resolveLocation2(
gl,
data,
false);
509 return data->hasLocation();
514 if (
data->hasLocation() ) {
515 return updateAttributeCache(
data);
517 impl::DataLoc *dl = &m_activeAttribMap.get(
data->name());
518 GLint location = dl->location();
519 if( 0 <= location ) {
520 data->setLocation(location);
524 if (
data->resolveLocation(
gl, m_shaderProgram->program()) ) {
525 dl = &updateDataLoc(*dl,
data,
true);
530 dl = &updateDataLoc(*dl,
data, forceMap);
548 return m_activeAttribMap.get(
name).enabled();
579 impl::DataLoc &dl = resolveLocation2(
gl,
name,
true);
583 const GLint location = dl.location();
593 ::glEnableVertexAttribArray(location);
620 impl::DataLoc &dl = resolveLocation2(
gl,
data,
true);
624 const GLint location = dl.location();
627 jau_INFO_PRINT(
"ShaderState: enableAttribute(2) failed, no data for: %s",
data->name());
632 jau_INFO_PRINT(
"ShaderState: enableAttribute(2): %s, loc: %d",
data->name(), location);
634 ::glEnableVertexAttribArray(
data->location());
658 impl::DataLoc &dl = resolveLocation2(
gl,
name,
false);
660 dl.setEnabled(
false);
662 const GLint location = dl.location();
672 ::glDisableVertexAttribArray(location);
698 impl::DataLoc &dl = resolveLocation2(
gl,
data,
false);
700 dl.setEnabled(
false);
702 const GLint location = dl.location();
705 jau_INFO_PRINT(
"ShaderState: disableAttribute(2) failed, no data for: %s",
data->name());
710 jau_INFO_PRINT(
"ShaderState: disableAttribute(2): %s, loc: %d",
data->name(), location);
712 ::glDisableVertexAttribArray(
data->location());
735 resolveLocation2(
gl,
data,
true);
736 if(!
data->hasLocation()) {
739 data->glVertexAttribPointer(
gl);
757 for (std::pair<const std::string_view, impl::DataLoc>& n : m_activeAttribMap.map()) {
758 impl::DataLoc& dl = n.second;
762 ::glDisableVertexAttribArray(
data->location());
763 data->setLocation(-1);
765 }
else if( dl.location() >= 0 ) {
766 ::glDisableVertexAttribArray(dl.location());
769 m_activeAttribMap.clear();
770 m_managedAttributes.clear();
791 for (std::pair<const std::string_view, impl::DataLoc>& n : m_activeAttribMap.map()) {
792 impl::DataLoc& dl = n.second;
796 ::glDisableVertexAttribArray(
data->location());
798 }
else if( dl.location() >= 0 ) {
799 ::glDisableVertexAttribArray(dl.location());
801 if( removeFromState ) {
802 dl.setEnabled(
false);
808 bool relocateAttribute(
const GL &
gl, impl::DataLoc &dl) {
810 if(
data->resolveLocation(
gl, m_shaderProgram->program()) ) {
812 jau_INFO_PRINT(
"ShaderState: relocateAttribute: %s, loc: %d", std::string(
data->name()),
data->location());
816 ::glEnableVertexAttribArray(
data->location());
819 if(
data->isVBO() ) {
820 ::glBindBuffer(GL_ARRAY_BUFFER,
data->vboName());
821 data->glVertexAttribPointer(
gl);
822 ::glBindBuffer(GL_ARRAY_BUFFER, 0);
824 data->glVertexAttribPointer(
gl);
852 void resetAllAttributes(
const GL& gl) {
853 if(!m_shaderProgram->linked())
throw RenderException(
"Program is not linked",
E_FILE_LINE);
858 for (std::pair<const std::string_view, impl::DataLoc>& n : m_activeAttribMap.map()) {
859 impl::DataLoc& dl = n.second;
862 if( relocateAttribute(gl, dl) ) {
863 dl.setLocation(data->location());
873 void setAttribute(
const GL& gl, impl::DataLoc &dl) {
877 const GLint loc = data->location();
880 ::glBindAttribLocation(m_shaderProgram->program(), loc,
string_t(
name).c_str());
884 ::glEnableVertexAttribArray(loc);
887 if( data->isVBO() ) {
888 ::glBindBuffer(GL_ARRAY_BUFFER, data->vboName());
889 data->glVertexAttribPointer(gl);
890 ::glBindBuffer(GL_ARRAY_BUFFER, 0);
892 data->glVertexAttribPointer(gl);
900 void setAllAttributes(
const GL& gl) {
901 for (std::pair<const std::string_view, impl::DataLoc>& n : m_activeAttribMap.map()) {
902 setAttribute(gl, n.second);
923 m_managedUniforms.push_back(&
data);
924 m_activeUniformMap.put(
data.name(), &
data);
926 m_activeUniformMap.remove(
data.name());
927 std::erase(m_managedUniforms, &
data);
933 return m_managedUniforms.end() != std::find(m_managedUniforms.begin(), m_managedUniforms.end(), &uniform);
951 m_activeUniformMap.put(
data.name(), &
data);
954 return m_activeUniformMap.remove(
data.name());
971 if (!
data.hasLocation()) {
974 if (!
data.resolveLocation(
gl, m_shaderProgram->program())) {
981 m_activeUniformMap.put(
data.name(), &
data);
1006 if (deactivateUnresolved) {
1007 m_activeUniformMap.remove(
data.name());
1023 for (
const std::pair<const std::string_view, GLUniformData *> &n : m_activeUniformMap.map()) {
1024 if(
send(
gl, *n.second, deactivateUnresolved) ) {
1033 return &uniform == m_activeUniformMap.get(uniform.
name());
1043 return m_activeUniformMap.get(
name);
1059 auto r = std::find_if(m_managedUniforms.begin(), m_managedUniforms.end(), [&
name](
GLUniformData *e) ->
bool { return name == e->name(); });
1060 if( m_managedUniforms.end() != r ) {
1071 m_activeUniformMap.clear();
1072 m_managedUniforms.clear();
1091 bool resetAllUniforms(
const GL&
gl)
noexcept {
1092 if (!m_shaderProgram->inUse()) {
1094 jau_INFO_PRINT(
"ShaderState: program not in use: %s", m_shaderProgram->toString());
1101 for (
const std::pair<const std::string_view, GLUniformData*> &n : m_activeUniformMap.map()) {
1103 if (
data->resolveLocation(
gl, m_shaderProgram->program())) {
1107 if (!
data->isBuffer()) {
1118 sb.append(
"ShaderState[\n ");
1119 if(m_shaderProgram) {
1120 sb.append(m_shaderProgram->toString());
1122 sb.append(
"ShaderProgram: null");
1124 sb.append(
"\n ],").append(
" activeAttributes [");
1125 for (
const std::pair<const std::string_view, impl::DataLoc>& n : m_activeAttribMap.map()) {
1126 const impl::DataLoc& dl = n.second;
1127 sb.append(
"\n ").append(n.first)
1128 .append(
": enabled ").append(
jau::to_string(dl.enabled())).append(
", ");
1130 sb.append(dl.data()->toString());
1135 sb.append(
"\n ],").append(
" managedAttributes [");
1137 sb.append(
"\n ").append(ad->toString());
1139 sb.append(
"\n ],").append(
" activeUniforms [");
1140 for (
const std::pair<const std::string_view, GLUniformData*>& n : m_activeUniformMap.map()) {
1143 sb.append(
"\n ").append(ud->
toString());
1146 sb.append(
"\n ],").append(
" managedUniforms [");
1148 sb.append(
"\n ").append(ud->toString());
1150 sb.append(
"\n ]").append(
"\n]");
1155 bool m_verbose =
false;
1157 bool m_resetAllShaderData =
false;
1159 typedef std::reference_wrapper<GLUniformData> GLUniformDataRef;
1162 std::vector<GLArrayDataSRef> m_managedAttributes;
1165 std::vector<GLUniformData*> m_managedUniforms;
ShaderState allows to sharing data between shader programs, while updating the attribute and uniform ...
void destroyAllData(GL &gl)
Calls release(gl, true, false, false).
bool isManaged(const GLArrayDataSRef &attribute) const
Returns true if given attribute is managed via manage()
bool resolveLocation(const GL &gl, GLUniformData &data)
Validates the uniform location or buffer-index.
GLUniformData * getManagedUniform(const stringview_t name)
Get the managed uniform data, previously owned.
bool isActive(const GLUniformData &uniform) const
Returns true if given uniform data is active, i.e. previously resolved/send and used in current progr...
bool inUse() const noexcept
Returns true if the shaderProgram() is in use, see ShaderProgram::inUse().
GLint getAttributeLocation(stringview_t name)
Get the previous cached vertex attribute location.
GLArrayDataSRef getAttribute(const stringview_t name) const
Get the previous cached vertex attribute data.
AttachableSRef detachObject(std::string_view key)
Removes attached object if exists and returns it, otherwise returns nullptr.
bool vertexAttribPointer(const GL &gl, const GLArrayDataSRef &data)
Set the GLArrayData vertex attribute data, if it's location is valid, i.e.
void setVerbose(bool v) noexcept
bool isManaged(const GLUniformData &uniform) const
Returns true if given uniform is managed via manage()
size_t sendAllUniforms(const GL &gl, bool deactivateUnresolved=false)
Send all active uniforms.
const ShaderProgramSRef & shaderProgram() const noexcept
Returns the attachedShaderProgram() or nullptr.
AttachableSRef getAttachedObject(std::string_view key) const
Returns the attached user object for the given name.
bool setActive(GLUniformData &data, bool active)
Activate or de-activate a managed GLUniform.
void manage(GLUniformData &data, bool enable=true)
Bind the GLUniform lifecycle to this ShaderState.
bool enableAttribute(const GL &gl, const stringview_t name)
Enables a vertex attribute array.
void disableAllAttributes(const GL &gl, bool removeFromState)
Disables all vertex attribute arrays.
GLUniformData * getActiveUniform(const stringview_t name)
Get the active uniform data, previously resolved/send and used in current program.
bool debug() const noexcept
void destroy(GL &gl)
Calls release(gl, true, true, true).
bool linked() const noexcept
Returns true if the shaderProgram() is linked, see ShaderProgram::linked().
AttachableSRef attachObject(std::string_view key, const AttachableSRef &obj)
Attaches user object for the given name, overwrites old mapping if exists.
bool disableAttribute(const GL &gl, const string_t &name)
Disables a vertex attribute array.
void releaseAllData(GL &gl)
Calls release(GL, bool, bool, bool) release(gl, false, false, false)}.
bool verbose() const noexcept
ShaderState() noexcept=default
void release(GL &gl, bool destroyBoundAttributes, bool destroyShaderProgram, bool destroyShaderCode)
bool resolveLocation(const GL &gl, const GLArrayDataSRef &data)
Validates the location of a shader attribute.
void releaseAllUniforms()
Releases all mapped uniform data and loses all indices.
void clearAttachedObjects()
Clears the attachment map.
void useProgram(GL &gl, bool on)
Turns the shader program on or off.
bool disableAttribute(const GL &gl, const GLArrayDataSRef &data)
Disables a vertex attribute array.
void destroyShaderProgram(GL &gl)
Calls release(gl, false, true, true).
bool isActive(const GLArrayDataSRef &attribute) const
bool isAttributeEnabled(const stringview_t name) const
void manage(const GLArrayDataSRef &attr, bool enable=true)
Binds or unbinds the GLArrayData lifecycle to this ShaderState.
void releaseAllAttributes(const GL &gl)
Releases all mapped vertex attribute data, disables all enabled attributes and loses all indices.
bool attachShaderProgram(GL &gl, const ShaderProgramSRef &prog, bool enable)
Attach or switch a shader program.
GLint resolveLocation(const GL &gl, stringview_t name)
Validates the location of a shader attribute.
bool send(const GL &gl, GLUniformData &data, bool deactivateUnresolved=false)
Sends the uniform data to the GPU if it's location is valid, i.e.
string_t toString(bool alsoUnlocated=DEBUG_STATE) const
bool enableAttribute(const GL &gl, const GLArrayDataSRef &data)
Enables a vertex attribute array, usually invoked by GLArrayDataEditable#enableBuffer(GL,...
bool isAttributeEnabled(const GLArrayDataSRef &data) const
static bool VERBOSE_STATE
void bindAttributeLocation(const GL &gl, GLint location, const GLArrayDataSRef &attr)
Binds a shader GLArrayData attribute to a location.
#define jau_INFO_PRINT(fmt,...)
Use for unconditional informal messages, prefix '[elapsed_time] Info: '.
std::string_view to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
HashMapWrap< std::string_view, Value_type, Novalue_type, no_value, jau::string_hash > StringViewHashMapWrap
StringHashViewMapWrap, generic std::unordered_map exposing a more higher level API,...
consteval_cxx20 std::string_view name() noexcept
std::ostream & operator<<(std::ostream &os, const T v)
std::shared_ptr< GLArrayData > GLArrayDataSRef
std::shared_ptr< ShaderProgram > ShaderProgramSRef
std::string_view stringview_t
std::shared_ptr< Attachable > AttachableSRef
jau::StringViewHashMapWrap< AttachableSRef, std::nullptr_t, nullptr > StringViewAttachables