Commit c4dd00fe authored by Frédéric Larue's avatar Frédéric Larue
Browse files

Preparing architecture in order to integrate compute shaders.

parent 8bebbd2e
/*
* (c) LSIIT, UMR CNRS/UdS
* Authors: F. Larue.
*
* See licence.txt for additional information.
*/
#include "GPUdefs.h"
#include "ComputeShader.h"
#include "Shader.h"
#include "VBO.h"
#include <fstream>
#include <string>
#include <iostream>
void GPU::ComputeShader::RecoverActiveUniforms()
{
m_Uniforms.clear();
m_Samplers.clear();
m_SamplerBinding.clear();
GLint count;
GLcharARB nameBuffer[512];
gpuAssert( glGetObjectParameterivARB( Id(), GL_OBJECT_ACTIVE_UNIFORMS_ARB, &count ) );
for( GLint i=0; i<count; ++i )
{
GLsizei length;
GLint size;
GLenum type;
gpuAssert( glGetActiveUniformARB(
Id(),
i,
sizeof(nameBuffer),
&length,
&size,
&type,
nameBuffer
) );
std::string name( nameBuffer );
size_t arraySymbolPos = name.find( "[" );
if( arraySymbolPos != std::string::npos )
name = name.substr( 0, arraySymbolPos );
switch( type )
{
case GL_SAMPLER_1D:
case GL_SAMPLER_2D:
case GL_SAMPLER_3D:
case GL_SAMPLER_CUBE:
case GL_SAMPLER_1D_SHADOW:
case GL_SAMPLER_2D_SHADOW:
case GL_SAMPLER_1D_ARRAY:
case GL_SAMPLER_2D_ARRAY:
case GL_SAMPLER_1D_ARRAY_SHADOW:
case GL_SAMPLER_2D_ARRAY_SHADOW:
case GL_SAMPLER_2D_MULTISAMPLE:
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
case GL_SAMPLER_CUBE_SHADOW:
case GL_SAMPLER_BUFFER:
case GL_SAMPLER_2D_RECT:
case GL_SAMPLER_2D_RECT_SHADOW:
case GL_INT_SAMPLER_1D:
case GL_INT_SAMPLER_2D:
case GL_INT_SAMPLER_3D:
case GL_INT_SAMPLER_CUBE:
case GL_INT_SAMPLER_1D_ARRAY:
case GL_INT_SAMPLER_2D_ARRAY:
case GL_INT_SAMPLER_2D_MULTISAMPLE:
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
case GL_INT_SAMPLER_BUFFER:
case GL_INT_SAMPLER_2D_RECT:
case GL_UNSIGNED_INT_SAMPLER_1D:
case GL_UNSIGNED_INT_SAMPLER_2D:
case GL_UNSIGNED_INT_SAMPLER_3D:
case GL_UNSIGNED_INT_SAMPLER_CUBE:
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
case GL_UNSIGNED_INT_SAMPLER_BUFFER:
case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
{
Uniform &smpl = m_Samplers[name];
gpuAssert( smpl.location = glGetUniformLocationARB( Id(), nameBuffer ) );
smpl.size = size;
smpl.type = type;
break;
}
default:
{
Uniform &unif = m_Uniforms[name];
gpuAssert( unif.location = glGetUniformLocationARB( Id(), nameBuffer ) );
unif.size = size;
unif.type = type;
break;
}
}
}
}
void GPU::ComputeShader::RecoverActiveAttributes()
{
m_Attributes.clear();
GLint count;
GLcharARB nameBuffer[512];
gpuAssert( glGetObjectParameterivARB( Id(), GL_OBJECT_ACTIVE_ATTRIBUTES_ARB, &count ) );
for( GLint i=0; i<count; ++i )
{
GLsizei length;
GLint size;
GLenum type;
gpuAssert( glGetActiveAttribARB(
Id(),
i,
sizeof(nameBuffer),
&length,
&size,
&type,
nameBuffer
) );
GLint attribId;
gpuAssert( attribId = glGetAttribLocationARB( Id(), nameBuffer ) );
if( attribId != -1 )
m_Attributes[ std::string(nameBuffer) ] = attribId;
}
}
bool GPU::ComputeShader::Link( std::string *logs )
{
if( !IsCreated() && !Allocate() )
return false;
if( m_Pg.IsInstantiated() )
gpuAssert( glAttachObjectARB( Id(), m_Pg.Id() ) );
gpuAssert( glLinkProgramARB( Id() ) );
GLint status;
gpuAssert( glGetObjectParameterivARB( Id(), GL_OBJECT_LINK_STATUS_ARB, &status ) );
if( !status )
{
if( logs )
*logs = GetLogs( Id() );
Unallocate();
return false;
}
RecoverActiveUniforms();
RecoverActiveAttributes();
return true;
}
GPU::ComputeShader& GPU::ComputeShader::Attach( const ComputePg &pg )
{
if( IsCreated() && m_Pg.IsInstantiated() )
gpuAssert( glDetachObjectARB( Id(), pg.Id() ) );
m_Pg = pg;
return *this;
}
GPU::ComputeShader& GPU::ComputeShader::DetachComputePg()
{
if( IsCreated() && m_Pg.IsInstantiated() )
gpuAssert( glDetachObjectARB( Id(), m_Pg.Id() ) );
m_Pg.Release();
return *this;
}
/*
bool GPU::ComputeShader::CreateFromFiles( const std::string &vshFilename,
const std::string &fshFilename )
{
VertPg vsh;
FragPg fsh;
return vsh.LoadFile( vshFilename ) &&
fsh.LoadFile( fshFilename ) &&
Create( vsh, fsh );
}
bool GPU::ComputeShader::CreateFromSources( const char *vshSourceStr,
const char *fshSourceStr )
{
VertPg vsh;
FragPg fsh;
return vsh.LoadSource( vshSourceStr ) &&
fsh.LoadSource( fshSourceStr ) &&
Create( vsh, fsh );
}
*/
void GPU::ComputeShader::Release()
{
if( m_Pg.Id() )
{
gpuAssert( glDetachObjectARB( Id(), m_Pg.Id() ) );
m_Pg.Release();
}
Unallocate();
m_Uniforms.clear();
m_Attributes.clear();
m_Samplers.clear();
m_SamplerBinding.clear();
}
void GPU::ComputeShader::SetUniform( const std::string& name,
const void *value )
{
UniformMap::iterator uu = m_Uniforms.find( name );
if( uu != m_Uniforms.end() )
{
GLuint activeProgBackup;
gpuAssert( activeProgBackup = glGetHandleARB( GL_PROGRAM_OBJECT_ARB ) );
gpuAssert( glUseProgramObjectARB( Id() ) );
Uniform &u = uu->second;
switch( u.type )
{
case GL_FLOAT: gpuAssert( glUniform1fvARB( u.location, u.size, (GLfloat*) value ) ); break;
case GL_FLOAT_VEC2_ARB: gpuAssert( glUniform2fvARB( u.location, u.size, (GLfloat*) value ) ); break;
case GL_FLOAT_VEC3_ARB: gpuAssert( glUniform3fvARB( u.location, u.size, (GLfloat*) value ) ); break;
case GL_FLOAT_VEC4_ARB: gpuAssert( glUniform4fvARB( u.location, u.size, (GLfloat*) value ) ); break;
case GL_DOUBLE: gpuAssert( glUniform1dv( u.location, u.size, (GLdouble*) value ) ); break;
case GL_DOUBLE_VEC2: gpuAssert( glUniform2dv( u.location, u.size, (GLdouble*) value ) ); break;
case GL_DOUBLE_VEC3: gpuAssert( glUniform3dv( u.location, u.size, (GLdouble*) value ) ); break;
case GL_DOUBLE_VEC4: gpuAssert( glUniform4dv( u.location, u.size, (GLdouble*) value ) ); break;
case GL_INT: gpuAssert( glUniform1ivARB( u.location, u.size, (GLint*) value ) ); break;
case GL_INT_VEC2_ARB: gpuAssert( glUniform2ivARB( u.location, u.size, (GLint*) value ) ); break;
case GL_INT_VEC3_ARB: gpuAssert( glUniform3ivARB( u.location, u.size, (GLint*) value ) ); break;
case GL_INT_VEC4_ARB: gpuAssert( glUniform4ivARB( u.location, u.size, (GLint*) value ) ); break;
case GL_BOOL_ARB: gpuAssert( glUniform1ivARB( u.location, u.size, (GLint*) value ) ); break;
case GL_BOOL_VEC2_ARB: gpuAssert( glUniform2ivARB( u.location, u.size, (GLint*) value ) ); break;
case GL_BOOL_VEC3_ARB: gpuAssert( glUniform3ivARB( u.location, u.size, (GLint*) value ) ); break;
case GL_BOOL_VEC4_ARB: gpuAssert( glUniform4ivARB( u.location, u.size, (GLint*) value ) ); break;
case GL_FLOAT_MAT2_ARB: gpuAssert( glUniformMatrix2fvARB( u.location, u.size, GL_FALSE, (GLfloat*) value ) ); break;
case GL_FLOAT_MAT3_ARB: gpuAssert( glUniformMatrix3fvARB( u.location, u.size, GL_FALSE, (GLfloat*) value ) ); break;
case GL_FLOAT_MAT4_ARB: gpuAssert( glUniformMatrix4fvARB( u.location, u.size, GL_FALSE, (GLfloat*) value ) ); break;
case GL_DOUBLE_MAT2: gpuAssert( glUniformMatrix2dv( u.location, u.size, GL_FALSE, (GLdouble*) value ) ); break;
case GL_DOUBLE_MAT3: gpuAssert( glUniformMatrix3dv( u.location, u.size, GL_FALSE, (GLdouble*) value ) ); break;
case GL_DOUBLE_MAT4: gpuAssert( glUniformMatrix4dv( u.location, u.size, GL_FALSE, (GLdouble*) value ) ); break;
}
gpuAssert( glUseProgramObjectARB( activeProgBackup ) );
}
}
void GPU::ComputeShader::SetSamplers( const std::string& name,
const GLint* texUnit )
{
UniformMap::iterator s = m_Samplers.find( name );
if( s != m_Samplers.end() )
{
GLuint activeProgBackup;
gpuAssert( activeProgBackup = glGetHandleARB( GL_PROGRAM_OBJECT_ARB ) );
gpuAssert( glUseProgramObjectARB( Id() ) );
gpuAssert( glUniform1ivARB( s->second.location, s->second.size, (GLint*) texUnit ) );
gpuAssert( glUseProgramObjectARB( activeProgBackup ) );
}
}
void GPU::ComputeShader::SetSamplers( const std::string& name,
const GLint firstTexUnit )
{
UniformMap::iterator s = m_Samplers.find( name );
if( s != m_Samplers.end() )
{
GLint *texUnits = new GLint [ s->second.size ];
for( GLint i=0; i<s->second.size; ++i )
texUnits[i] = firstTexUnit + i;
GLuint activeProgBackup;
gpuAssert( activeProgBackup = glGetHandleARB( GL_PROGRAM_OBJECT_ARB ) );
gpuAssert( glUseProgramObjectARB( Id() ) );
gpuAssert( glUniform1ivARB( s->second.location, s->second.size, texUnits ) );
gpuAssert( glUseProgramObjectARB( activeProgBackup ) );
delete[] texUnits;
}
}
void GPU::ComputeShader::SetAttrib( const std::string& name,
VBOAttribBuffer *attrib )
{
attrib->SetLocation( AttribLoc(name) );
}
void GPU::ComputeShader::UniformNames( std::vector<std::string> &names ) const
{
names.clear();
names.reserve( m_Uniforms.size() );
for( auto &u : m_Uniforms )
names.push_back( u.first );
}
void GPU::ComputeShader::SamplerNames( std::vector<std::string> &names ) const
{
names.clear();
names.reserve( m_Samplers.size() );
for( auto& s : m_Samplers )
names.push_back( s.first );
}
void GPU::ComputeShader::AttribNames( std::vector<std::string> &names ) const
{
names.clear();
names.reserve( m_Attributes.size() );
for( auto& a : m_Attributes )
names.push_back( a.first );
}
bool GPU::CreateShaderFromSources( GPU::ComputeShader &shader,
const char *pgSrc,
std::string *logs )
{
shader.Release();
if( pgSrc && pgSrc[0] != '\0' )
{
GPU::ComputeShader::ComputePg pg;
if( !pg.CompileSrcString( pgSrc, logs ) )
{
if( logs )
*logs = std::string(__FUNCTION__) + " - Vertex program compilation error:\n" + *logs + '\n';
return false;
}
shader.Attach( pg );
}
if( !shader.Link( logs ) )
{
if( logs )
*logs = std::string(__FUNCTION__) + " - ComputeShader link error:\n" + *logs + '\n';
return false;
}
return true;
}
/*
* (c) LSIIT, UMR CNRS/UdS
* Authors: F. Larue.
*
* See licence.txt for additional information.
*/
#ifndef __GPU__COMPUTESHADER_H__
#define __GPU__COMPUTESHADER_H__
#include "GPUdefs.h"
#include "InstantiatedObject.h"
#include "Shader.h"
#include <string>
#include <map>
/*
*
* CLASS DECLARATION.
*
*/
namespace GPU
{
class VBO;
class VBOAttribBuffer;
class ComputeShader : public GenericShader
{
/******************\
| Internal type(s) |
\******************/
public:
struct Uniform
{
GLint location;
GLint size;
GLenum type;
};
class ComputePg : public PgObject
{
public:
inline bool CompileSrcFile( const std::string &filename,
std::string *logs = NULL ) { return PgObject::CompileSrcFile( filename, GL_COMPUTE_SHADER, logs ); }
inline bool CompileSrcString( const char *sourceString,
std::string *logs = NULL ) { return PgObject::CompileSrcString( sourceString, GL_COMPUTE_SHADER, logs ); }
};
static ComputePg ComputePgFromFile( const std::string &filename,
std::string *logs = NULL ) { ComputePg pg; return (pg.CompileSrcFile(filename,logs)? pg : ComputePg()); }
static ComputePg ComputePgFromString( const char *sourceString,
std::string *logs = NULL ) { ComputePg pg; return (pg.CompileSrcString(sourceString,logs)? pg : ComputePg()); }
private:
typedef std::map<std::string,Uniform> UniformMap;
typedef std::map<std::string,GLint> AttribMap;
typedef std::map<GLint,Texture*> SamplerBindingMap;
typedef std::map<GLint,VBOAttribBuffer*> AttribBindingMap;
/********************\
| Member variable(s) |
\********************/
private:
ComputePg m_Pg;
UniformMap m_Uniforms;
UniformMap m_Samplers;
AttribMap m_Attributes;
SamplerBindingMap m_SamplerBinding;
/*****************************\
| Constructor(s) / destructor |
\*****************************/
public:
inline ComputeShader() : GenericShader() {}
inline ~ComputeShader() { Release(); }
/********************\
| Member function(s) |
\********************/
protected:
void RecoverActiveUniforms();
void RecoverActiveAttributes();
public:
bool Link( std::string *logs = NULL );
ComputeShader& Attach( const ComputePg& pg );
inline bool AttachAndLink( const ComputePg& pg,
std::string *logs = NULL ) { Attach(pg); return Link(logs); }
ComputeShader& DetachComputePg();
void Release();
inline const ComputePg& ComputeProgram() const { return m_Pg; }
inline void Bind() { gpuAssert( glUseProgramObjectARB( Id() ) ); BindSamplers(); }
inline void Unbind() { UnbindSamplers(); gpuAssert( glUseProgramObjectARB( 0 ) ); }
void SetUniform( const std::string& name,
const void *value );
inline void SetSampler( const std::string& name,
const GLint texUnit ) { SetSamplers( name, &texUnit ); }
void SetSamplers( const std::string& name,
const GLint* texUnit );
void SetSamplers( const std::string& name,
const GLint firstTexUnit );
void SetAttrib( const std::string& name,
VBOAttribBuffer *attrib );
void UniformNames( std::vector<std::string> &names ) const;
void SamplerNames( std::vector<std::string> &names ) const;
void AttribNames( std::vector<std::string> &names ) const;
inline const Uniform* UniformLoc( const std::string& name ) const
{
UniformMap::const_iterator u = m_Uniforms.find( name );
return (u!=m_Uniforms.end())? &u->second : NULL;
}
inline GLint SamplerLoc( const std::string& name ) const
{
UniformMap::const_iterator s = m_Samplers.find( name );
return (s!=m_Samplers.end())? s->second.location : -1;
}
inline GLint AttribLoc( const std::string& name ) const
{
AttribMap::const_iterator a = m_Attributes.find( name );
return (a!=m_Attributes.end())? a->second : -1;
}
inline void SetSamplerBinding( const std::string& name, Texture &sampler ) { SetSamplerBinding( name, &sampler ); }
inline void SetSamplerBinding( const std::string& name, Texture *sampler )
{
GLint loc = SamplerLoc( name );
if( loc >= 0 )
m_SamplerBinding[loc] = sampler;
}
inline void RemoveSamplerBinding( const std::string& name )
{
auto sb = m_SamplerBinding.find( SamplerLoc(name) );
if( sb != m_SamplerBinding.end() )
m_SamplerBinding.erase( sb );
}
inline void RemoveAllSamplerBindings()
{
m_SamplerBinding.clear();
}
private:
inline void BindSamplers()
{
GLint texUnit = 0;
for( auto sb=m_SamplerBinding.begin(); sb!=m_SamplerBinding.end(); ++sb )
{
sb->second->Bind( texUnit );
gpuAssert( glUniform1iARB( sb->first, texUnit++ ) );
}
}
inline void UnbindSamplers()
{
for( auto sb=m_SamplerBinding.begin(); sb!=m_SamplerBinding.end(); ++sb )
sb->second->Unbind();
}
};
bool CreateShaderFromSources( GPU::ComputeShader &shader,
const char *pgSrc,
std::string *logs = NULL );
inline bool CreateShaderFromSources( GPU::ComputeShader &shader,
const std::string &pgSrc,
std::string *logs = NULL ) { return CreateShaderFromSources( shader, pgSrc.c_str(), logs ); }
};
#endif //__GPU__COMPUTESHADER_H__
......@@ -16,14 +16,14 @@
bool GPU::Shader::PgObject::Allocate()
bool GPU::GenericShader::PgObject::Allocate()
{
gpuAssert( m_Id = glCreateShaderObjectARB( m_PgType ) );
return m_Id != 0;
}
bool GPU::Shader::PgObject::Unallocate()
bool GPU::GenericShader::PgObject::Unallocate()
{
gpuAssert( glDeleteObjectARB( m_Id ) );
m_Id = 0;
......@@ -31,9 +31,9 @@ bool GPU::Shader::PgObject::Unallocate()
}
bool GPU::Shader::PgObject::CompileSrcFile( const std::string &filename,
const GLenum pgType,
std::string *logs )
bool GPU::GenericShader::PgObject::CompileSrcFile( const std::string &filename,
const GLenum pgType,
std::string *logs )
{
// Open the source files.
std::ifstream file( filename.c_str(), std::ios::binary );
......@@ -60,7 +60,7 @@ bool GPU::Shader::PgObject::CompileSrcFile( const std::string &filename,
}
bool GPU::Shader::PgObject::CompileSrcString( const char *sourceString,
bool GPU::GenericShader::PgObject::CompileSrcString( const char *sourceString,
const GLenum pgType,
std::string *logs )
{
......@@ -90,7 +90,7 @@ bool GPU::Shader::PgObject::CompileSrcString( const char *sourceString,